Merge branch 'master' into stable
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7eb3585..3fdf6ca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,7 +16,7 @@
 ###
 ## global definitions
 ###
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.1)
 project(Corinthia)
 
 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
@@ -36,7 +36,7 @@
 endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
 
 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-    set(CMAKE_C_FLAGS "-std=c99 -D_GNU_SOURCE -g")
+    set(CMAKE_C_FLAGS "-std=c99 -D_GNU_SOURCE -g -fPIC")
     set(LIBS ${LIBS} m pthread xml2 z SDL2 SDL2_image)
 endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 
@@ -46,7 +46,11 @@
     set(LIB_DIRS
 	${PROJECT_SOURCE_DIR}/external/download/lib)
     set(LIBS ${LIBS} libxml2 zdll iconv SDL2 SDL2_image)
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4090 /wd4996")
+    if(${CMAKE_GENERATOR_PLATFORM} MATCHES "x64")
+        set(CMAKE_C_FLAGS "/DWIN64 /D_WINDOWS /W3 /wd4090 /wd4996")
+    else(${CMAKE_GENERATOR_PLATFORM} MATCHES "x64")
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4090 /wd4996")
+    endif(${CMAKE_GENERATOR_PLATFORM} MATCHES "x64")
 endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
 
 
@@ -58,3 +62,4 @@
 add_subdirectory(consumers/dftest/src)
 add_subdirectory(consumers/dfconvert/src)
 add_subdirectory(consumers/dfutil/src)
+#TEST add_subdirectory(consumers/corinthia/src)
diff --git a/DocFormats/CMakeLists.txt b/DocFormats/CMakeLists.txt
index c21a05f..b371c09 100644
--- a/DocFormats/CMakeLists.txt
+++ b/DocFormats/CMakeLists.txt
@@ -16,7 +16,6 @@
 ###
 ## global definitions
 ###
-cmake_minimum_required(VERSION 2.8)
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 
diff --git a/DocFormats/DocFormats.c b/DocFormats/DocFormats.c
index ecf1616..431970a 100644
--- a/DocFormats/DocFormats.c
+++ b/DocFormats/DocFormats.c
@@ -1,3 +1,20 @@
+// 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.
+
 void DocFormats()
 {
 }
diff --git a/DocFormats/api/CMakeLists.txt b/DocFormats/api/CMakeLists.txt
index e0146ef..148be77 100644
--- a/DocFormats/api/CMakeLists.txt
+++ b/DocFormats/api/CMakeLists.txt
@@ -56,6 +56,7 @@
 include_directories(../core/src/xml)
 include_directories(../filters/latex/src)
 include_directories(../filters/odf/src)
+include_directories(../filters/odf/src/text)
 include_directories(../filters/ooxml/src/common)
 include_directories(../filters/ooxml/src/word)
 include_directories(../filters/ooxml/src/word/formatting)
diff --git a/DocFormats/api/headers/DocFormats/DFError.h b/DocFormats/api/headers/DocFormats/DFError.h
index 2876007..fb6343f 100644
--- a/DocFormats/api/headers/DocFormats/DFError.h
+++ b/DocFormats/api/headers/DocFormats/DFError.h
@@ -1,32 +1,25 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFError_h
 #define DocFormats_DFError_h
 
 #include <stdarg.h>
 
-// It's really not nice having this here, but is the only way to get the compiler to typecheck the
-// DFErrorFormat arguments when such functionality is available.
-#ifndef ATTRIBUTE_FORMAT
-#ifdef _MSC_VER
-#define ATTRIBUTE_FORMAT(archetype,index,first)
-#else
-#define ATTRIBUTE_FORMAT(archetype,index,first) __attribute__((format(archetype,index,first)))
-#endif
-#endif
-
 typedef struct DFError DFError;
 
 void DFErrorSetPosix(DFError **error, int code);
diff --git a/DocFormats/api/headers/DocFormats/DFStorage.h b/DocFormats/api/headers/DocFormats/DFStorage.h
index 34bee44..2c27293 100644
--- a/DocFormats/api/headers/DocFormats/DFStorage.h
+++ b/DocFormats/api/headers/DocFormats/DFStorage.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFStorage_h
 #define DocFormats_DFStorage_h
diff --git a/DocFormats/api/headers/DocFormats/DFXMLForward.h b/DocFormats/api/headers/DocFormats/DFXMLForward.h
index ddfa7f6..6a2a740 100644
--- a/DocFormats/api/headers/DocFormats/DFXMLForward.h
+++ b/DocFormats/api/headers/DocFormats/DFXMLForward.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFXMLForward_h
 #define DocFormats_DFXMLForward_h
diff --git a/DocFormats/api/headers/DocFormats/DocFormats.h b/DocFormats/api/headers/DocFormats/DocFormats.h
index 6de204f..f5c3472 100644
--- a/DocFormats/api/headers/DocFormats/DocFormats.h
+++ b/DocFormats/api/headers/DocFormats/DocFormats.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include <DocFormats/Operations.h>
 #include <DocFormats/Formats.h>
diff --git a/DocFormats/api/headers/DocFormats/Formats.h b/DocFormats/api/headers/DocFormats/Formats.h
index fb83f40..49c8aee 100644
--- a/DocFormats/api/headers/DocFormats/Formats.h
+++ b/DocFormats/api/headers/DocFormats/Formats.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_Formats_h
 #define DocFormats_Formats_h
diff --git a/DocFormats/api/headers/DocFormats/Operations.h b/DocFormats/api/headers/DocFormats/Operations.h
index 804bebc..1bb6ee2 100644
--- a/DocFormats/api/headers/DocFormats/Operations.h
+++ b/DocFormats/api/headers/DocFormats/Operations.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_Operations_h
 #define DocFormats_Operations_h
diff --git a/DocFormats/api/src/Formats.c b/DocFormats/api/src/Formats.c
index 20d77dd..289c288 100644
--- a/DocFormats/api/src/Formats.c
+++ b/DocFormats/api/src/Formats.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include <DocFormats/Formats.h>
 #include "DFPlatform.h"
diff --git a/DocFormats/api/src/Operations.c b/DocFormats/api/src/Operations.c
index 18575cd..a9f9bb2 100644
--- a/DocFormats/api/src/Operations.c
+++ b/DocFormats/api/src/Operations.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include <DocFormats/Operations.h>
@@ -18,11 +21,14 @@
 #include "DFString.h"
 #include <DocFormats/DFStorage.h>
 #include "Word.h"
+#include "ODFText.h"
 #include "DFHTML.h"
 #include "DFDOM.h"
 #include "DFXML.h"
 #include "DFZipFile.h"
 #include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
 
 struct DFConcreteDocument {
     size_t retainCount;
@@ -35,15 +41,66 @@
     DFDocument *htmlDoc;
 };
 
+/**
+ * Compute a hash of the set of all XML files in the archive. When the get operation is executed,
+ * this hash is stored in the HTML file, as a record of the document from which it was generated.
+ * When the put operation is executed, the hash is compared with that of the HTML file, and an error
+ * reported if a mismatch occurs.
+ *
+ * This check ensures that put can only be executed with HTML documents that were genuinely
+ * generated from this exact (version of the) document, and thus can be safely assumed to have id
+ * attributes that correctly match elements in the HTML document to elements in the original XML
+ * file(s) from which they were generated, avoiding corruption during the update process.
+ *
+ * If someone tries to call put with a HTML document that was not originally created from this exact
+ * concrete document, the operation will fail.
+ */
+static int computeXMLHash(DFStorage *storage, DFHashCode *result, DFError **error)
+{
+    int ok = 0;
+    *result = 0;
+
+    DFHashCode hash = 0;
+    DFHashBegin(hash);
+    const char **filenames = DFStorageList(storage,error);
+    if (filenames == NULL)
+        goto end;
+    for (int i = 0; filenames[i]; i++) {
+        unsigned char *buf = NULL;
+        size_t nbytes = 0;
+        if (!DFStorageRead(storage,filenames[i],(void **)&buf,&nbytes,error)) {
+            DFErrorFormat(error,"%s: %s",filenames[i],DFErrorMessage(error));
+            goto end;
+        }
+        // The hash algorithm works on 32-bit integers; add 4 NULL bytes at the end of the buffer to
+        // ensure its entire contents are taken into account when computing the hash.
+        buf = xrealloc(buf,nbytes+4);
+        memset(&buf[nbytes],0,4);
+        uint32_t *intbuf = (uint32_t *)buf;
+        for (size_t pos = 0; pos < (nbytes+3)/4; pos++)
+            DFHashUpdate(hash,intbuf[pos]);
+        free(buf);
+    }
+    DFHashEnd(hash);
+    *result = hash;
+    ok = 1;
+
+end:
+    free(filenames);
+    return ok;
+}
+
 DFConcreteDocument *DFConcreteDocumentNew(DFStorage *storage)
 {
-    DFConcreteDocument *concrete = (DFConcreteDocument *)calloc(1,sizeof(DFConcreteDocument));
+    DFConcreteDocument *concrete = 
+      (DFConcreteDocument *)xcalloc(1,sizeof(DFConcreteDocument));
     concrete->retainCount = 1;
     concrete->storage = DFStorageRetain(storage);
     return concrete;
 }
 
-DFConcreteDocument *DFConcreteDocumentCreateFile(const char *filename, DFError **error)
+DFConcreteDocument
+*DFConcreteDocumentCreateFile(const char *filename, DFError **error)
 {
     DFFileFormat format = DFFileFormatFromFilename(filename);
     switch (format) {
@@ -53,20 +110,24 @@
         case DFFileFormatOdt:
         case DFFileFormatOds:
         case DFFileFormatOdp: {
-            DFStorage *storage = DFStorageCreateZip(filename,error);
+            DFStorage *storage = DFStorageCreateZip(filename, error);
             if (storage == NULL)
                 return NULL;;
-            DFConcreteDocument *concrete = DFConcreteDocumentNew(storage);
+            DFConcreteDocument *concrete =
+              DFConcreteDocumentNew(storage);
             DFStorageRelease(storage);
             return concrete;
         }
         default:
-            DFErrorFormat(error,"Unsupported format for DFConcreteDocumentCreateFile");
+            DFErrorFormat(error,
+                          "Unsupported format for "
+                          "DFConcreteDocumentCreateFile");
             return NULL;
     }
 }
 
-DFConcreteDocument *DFConcreteDocumentOpenFile(const char *filename, DFError **error)
+DFConcreteDocument 
+*DFConcreteDocumentOpenFile(const char *filename, DFError **error)
 {
     DFFileFormat format = DFFileFormatFromFilename(filename);
     switch (format) {
@@ -79,17 +140,20 @@
             DFStorage *storage = DFStorageOpenZip(filename,error);
             if (storage == NULL)
                 return NULL;;
-            DFConcreteDocument *concrete = DFConcreteDocumentNew(storage);
+            DFConcreteDocument *concrete =
+              DFConcreteDocumentNew(storage);
             DFStorageRelease(storage);
             return concrete;
         }
         default:
-            DFErrorFormat(error,"Unsupported format for DFConcreteDocumentCreateFile");
+            DFErrorFormat(error,"Unsupported format for" 
+                          "DFConcreteDocumentCreateFile");
             return NULL;
     }
 }
 
-DFConcreteDocument *DFConcreteDocumentRetain(DFConcreteDocument *concrete)
+DFConcreteDocument 
+*DFConcreteDocumentRetain(DFConcreteDocument *concrete)
 {
     if (concrete != NULL)
         concrete->retainCount++;
@@ -107,13 +171,15 @@
 
 DFAbstractDocument *DFAbstractDocumentNew(DFStorage *storage)
 {
-    DFAbstractDocument *abstract = (DFAbstractDocument *)calloc(1,sizeof(DFAbstractDocument));
+    DFAbstractDocument *abstract =
+      (DFAbstractDocument *)xcalloc(1,sizeof(DFAbstractDocument));
     abstract->retainCount = 1;
     abstract->storage = DFStorageRetain(storage);
     return abstract;
 }
 
-DFAbstractDocument *DFAbstractDocumentRetain(DFAbstractDocument *abstract)
+DFAbstractDocument
+*DFAbstractDocumentRetain(DFAbstractDocument *abstract)
 {
     if (abstract != NULL)
         abstract->retainCount++;
@@ -135,23 +201,50 @@
     return abstract->htmlDoc;
 }
 
-void DFAbstractDocumentSetHTML(DFAbstractDocument *abstract, DFDocument *htmlDoc)
+void DFAbstractDocumentSetHTML(DFAbstractDocument *abstract,
+                               DFDocument *htmlDoc)
 {
     DFDocumentRelease(abstract->htmlDoc);
     abstract->htmlDoc = DFDocumentRetain(htmlDoc);
 }
 
-int DFGet(DFConcreteDocument *concrete, DFAbstractDocument *abstract, DFError **error)
+int DFGet(DFConcreteDocument *concrete,
+          DFAbstractDocument *abstract,
+          DFError **error)
 {
     if (DFStorageFormat(abstract->storage) != DFFileFormatHTML) {
-        DFErrorFormat(error,"Abstract document must be in HTML format");
+        DFErrorFormat(error,
+                      "Abstract document must be in HTML format");
         return 0;
     }
 
+    DFHashCode hash = 0;
+    if (!computeXMLHash(concrete->storage,&hash,error))
+        return 0;
+    char hashstr[100];
+    snprintf(hashstr,100,"%X",hash);
+
+    char hashprefix[100];
+    snprintf(hashprefix,100,"%s-",hashstr);
+    const char *idPrefix;
+    if (DFStorageExists(abstract->storage,"test-mode"))
+        idPrefix = NULL;
+    else
+        idPrefix = hashprefix;
+
     DFDocument *htmlDoc = NULL;
     switch (DFStorageFormat(concrete->storage)) {
         case DFFileFormatDocx:
-            htmlDoc = WordGet(concrete->storage,abstract->storage,error);
+            htmlDoc = WordGet(concrete->storage,
+                              abstract->storage,
+                              idPrefix,
+                              error);
+            break;
+        case DFFileFormatOdt:
+            htmlDoc = ODFTextGet(concrete->storage,
+                                 abstract->storage,
+                                 idPrefix,
+                                 error);
             break;
         default:
             DFErrorFormat(error,"Unsupported file format");
@@ -159,24 +252,66 @@
     }
 
     if (htmlDoc == NULL)
-        return 0;
+        return 0;;
+
+    // Store a hash of the concrete document in the HTML file, so we can check it in DFPut()
+    HTMLMetaSet(htmlDoc,"corinthia-document-hash",hashstr);
 
     DFDocumentRelease(abstract->htmlDoc);
     abstract->htmlDoc = htmlDoc;
     return 1;
 }
 
-int DFPut(DFConcreteDocument *concreteDoc, DFAbstractDocument *abstractDoc, DFError **error)
+int DFPut(DFConcreteDocument *concreteDoc,
+          DFAbstractDocument *abstractDoc,
+          DFError **error)
 {
     if (DFStorageFormat(abstractDoc->storage) != DFFileFormatHTML) {
-        DFErrorFormat(error,"Abstract document must be in HTML format");
+        DFErrorFormat(error,
+                      "Abstract document must be in HTML format");
         return 0;
     }
 
+    // Check that the document hash in the HTML file matches that of the concrete document. This
+    // ensures that we're using a HTML file that was generated from this exact document (see above)
+    // and can rely on the element mappings from the id attributes. This comparison is ignored
+    // for test cases, which specify the special value "ignore" in the meta tag.
+    DFHashCode expectedHash = 0;
+    if (!computeXMLHash(concreteDoc->storage,&expectedHash,error))
+        return 0;;
+    DFHashCode actualHash = 0;
+    int hashMatches = 0;
+    const char *hashstr = HTMLMetaGet(abstractDoc->htmlDoc,"corinthia-document-hash");
+    if ((hashstr != NULL) && (sscanf(hashstr,"%X",&actualHash) == 1))
+        hashMatches = (expectedHash == actualHash);
+    if (!hashMatches && !DFStringEquals(hashstr,"ignore")) {
+        DFErrorFormat(error,"HTML document was generated from a different file to the one being updated");
+        return 0;
+    }
+
+    char hashprefix[100];
+    snprintf(hashprefix,100,"%s-",hashstr);
+    const char *idPrefix;
+    if (DFStringEquals(hashstr,"ignore"))
+        idPrefix = NULL;
+    else
+        idPrefix = hashprefix;
+
     int ok = 0;
     switch (DFStorageFormat(concreteDoc->storage)) {
         case DFFileFormatDocx:
-            ok = WordPut(concreteDoc->storage,abstractDoc->storage,abstractDoc->htmlDoc,error);
+            ok = WordPut(concreteDoc->storage,
+                         abstractDoc->storage,
+                         abstractDoc->htmlDoc,
+                         idPrefix,
+                         error);
+            break;
+        case DFFileFormatOdt:
+            ok = ODFTextPut(concreteDoc->storage,
+                            abstractDoc->storage,
+                            abstractDoc->htmlDoc,
+                            idPrefix,
+                            error);
             break;
         default:
             DFErrorFormat(error,"Unsupported file format");
@@ -185,17 +320,29 @@
     return ok;
 }
 
-int DFCreate(DFConcreteDocument *concreteDoc, DFAbstractDocument *abstractDoc, DFError **error)
+int DFCreate(DFConcreteDocument *concreteDoc,
+             DFAbstractDocument *abstractDoc,
+             DFError **error)
 {
     if (DFStorageFormat(abstractDoc->storage) != DFFileFormatHTML) {
-        DFErrorFormat(error,"Abstract document must be in HTML format");
+        DFErrorFormat(error,
+                      "Abstract document must be in HTML format");
         return 0;
     }
 
     int ok = 0;
     switch (DFStorageFormat(concreteDoc->storage)) {
         case DFFileFormatDocx:
-            ok = WordCreate(concreteDoc->storage,abstractDoc->storage,abstractDoc->htmlDoc,error);
+            ok = WordCreate(concreteDoc->storage,
+                            abstractDoc->storage,
+                            abstractDoc->htmlDoc,
+                            error);
+            break;
+        case DFFileFormatOdt:
+            ok = ODFTextCreate(concreteDoc->storage,
+                               abstractDoc->storage,
+                               abstractDoc->htmlDoc,
+                               error);
             break;
         default:
             DFErrorFormat(error,"Unsupported file format");
@@ -204,34 +351,48 @@
     return ok;
 }
 
-int DFGetFile(const char *concreteFilename, const char *abstractFilename, DFError **error)
+int DFGetFile(const char *concreteFilename,
+              const char *abstractFilename,
+              DFError **error)
 {
     int r = 0;
     char *abstractPath = DFPathDirName(abstractFilename);
-    DFStorage *abstractStorage = DFStorageNewFilesystem(abstractPath,DFFileFormatHTML);
+    DFStorage *abstractStorage =
+      DFStorageNewFilesystem(abstractPath, DFFileFormatHTML);
     DFConcreteDocument *concreteDoc = NULL;
     DFAbstractDocument *abstractDoc = NULL;
 
-    concreteDoc = DFConcreteDocumentOpenFile(concreteFilename,error);
+    concreteDoc = DFConcreteDocumentOpenFile(concreteFilename, error);
     if (concreteDoc == NULL) {
-        DFErrorFormat(error,"%s: %s",concreteFilename,DFErrorMessage(error));
+        DFErrorFormat(error, "%s: %s",
+                      concreteFilename,
+                      DFErrorMessage(error));
         goto end;
     }
 
     abstractDoc = DFAbstractDocumentNew(abstractStorage);
 
-    if (!DFGet(concreteDoc,abstractDoc,error) || (abstractDoc->htmlDoc == NULL)) {
-        DFErrorFormat(error,"%s: %s",concreteFilename,DFErrorMessage(error));
+    if (!DFGet(concreteDoc, abstractDoc, error)
+        || (abstractDoc->htmlDoc == NULL)) {
+        DFErrorFormat(error, "%s: %s",
+                      concreteFilename,
+                      DFErrorMessage(error));
         goto end;
     }
 
     if (DFFileExists(abstractFilename)) {
-        DFErrorFormat(error,"%s: File already exists",abstractFilename);
+        DFErrorFormat(error,
+                      "%s: File already exists",
+                      abstractFilename);
         goto end;
     }
 
-    if (!DFSerializeXMLFile(abstractDoc->htmlDoc,0,0,abstractFilename,error)) {
-        DFErrorFormat(error,"%s: %s",abstractFilename,DFErrorMessage(error));
+    if (!DFSerializeXMLFile(abstractDoc->htmlDoc,
+                            0, 0,
+                            abstractFilename,error)) {
+        DFErrorFormat(error, "%s: %s",
+                      abstractFilename,
+                      DFErrorMessage(error));
         goto end;
     }
 
@@ -245,31 +406,38 @@
     return r;
 }
 
-int DFPutFile(const char *concreteFilename, const char *abstractFilename, DFError **error)
+int DFPutFile(const char *concreteFilename,
+              const char *abstractFilename,
+              DFError **error)
 {
     int ok = 0;
     DFDocument *htmlDoc2 = NULL;
     char *abstractPath = DFPathDirName(abstractFilename);
-    DFStorage *abstractStorage2 = DFStorageNewFilesystem(abstractPath,DFFileFormatHTML);
+    DFStorage *abstractStorage2 =
+      DFStorageNewFilesystem(abstractPath, DFFileFormatHTML);
     DFConcreteDocument *concreteDoc = NULL;
     DFAbstractDocument *abstractDoc = NULL;
 
-    htmlDoc2 = DFParseHTMLFile(abstractFilename,0,error);
+    htmlDoc2 = DFParseHTMLFile(abstractFilename, 0, error);
     if (htmlDoc2 == NULL) {
-        DFErrorFormat(error,"%s: %s",abstractFilename,DFErrorMessage(error));
+        DFErrorFormat(error,"%s: %s",
+                      abstractFilename,
+                      DFErrorMessage(error));
         goto end;
     }
 
-    concreteDoc = DFConcreteDocumentOpenFile(concreteFilename,error);
+    concreteDoc = DFConcreteDocumentOpenFile(concreteFilename, error);
     if (concreteDoc == NULL) {
-        DFErrorFormat(error,"%s: %s",concreteFilename,DFErrorMessage(error));
+        DFErrorFormat(error, "%s: %s",
+                      concreteFilename,
+                      DFErrorMessage(error));
         goto end;
     }
 
     abstractDoc = DFAbstractDocumentNew(abstractStorage2);
     abstractDoc->htmlDoc = DFDocumentRetain(htmlDoc2);
 
-    ok = DFPut(concreteDoc,abstractDoc,error);
+    ok = DFPut(concreteDoc, abstractDoc, error);
 
 end:
     DFDocumentRelease(htmlDoc2);
@@ -280,31 +448,39 @@
     return ok;
 }
 
-int DFCreateFile(const char *concreteFilename, const char *abstractFilename, DFError **error)
+int DFCreateFile(const char *concreteFilename,
+                 const char *abstractFilename,
+                 DFError **error)
 {
     int ok = 0;
     DFDocument *htmlDoc = NULL;
     char *abstractPath = DFPathDirName(abstractFilename);
-    DFStorage *abstractStorage = DFStorageNewFilesystem(abstractPath,DFFileFormatHTML);
+    DFStorage *abstractStorage =
+      DFStorageNewFilesystem(abstractPath, DFFileFormatHTML);
     DFConcreteDocument *concreteDoc = NULL;
     DFAbstractDocument *abstractDoc = NULL;
 
-    htmlDoc = DFParseHTMLFile(abstractFilename,0,error);
+    htmlDoc = DFParseHTMLFile(abstractFilename, 0, error);
     if (htmlDoc == NULL) {
-        DFErrorFormat(error,"%s: %s",abstractFilename,DFErrorMessage(error));
+        DFErrorFormat(error,"%s: %s",
+                      abstractFilename,
+                      DFErrorMessage(error));
         goto end;
     }
 
-    concreteDoc = DFConcreteDocumentCreateFile(concreteFilename,error);
+    concreteDoc =
+      DFConcreteDocumentCreateFile(concreteFilename, error);
     if (concreteDoc == NULL) {
-        DFErrorFormat(error,"%s: %s",concreteFilename,DFErrorMessage(error));
+        DFErrorFormat(error, "%s: %s",
+                      concreteFilename,
+                      DFErrorMessage(error));
         goto end;
     }
 
     abstractDoc = DFAbstractDocumentNew(abstractStorage);
     abstractDoc->htmlDoc = DFDocumentRetain(htmlDoc);
 
-    ok = DFCreate(concreteDoc,abstractDoc,error);
+    ok = DFCreate(concreteDoc, abstractDoc, error);
 
 end:
     DFDocumentRelease(htmlDoc);
diff --git a/DocFormats/api/tests/APITests.c b/DocFormats/api/tests/APITests.c
index 57659b4..73cbe6e 100644
--- a/DocFormats/api/tests/APITests.c
+++ b/DocFormats/api/tests/APITests.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFUnitTest.h"
 #include <stddef.h>
diff --git a/DocFormats/core/src/common/DFBDT.c b/DocFormats/core/src/common/DFBDT.c
index 8a34599..db96e3b 100644
--- a/DocFormats/core/src/common/DFBDT.c
+++ b/DocFormats/core/src/common/DFBDT.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFBDT.h"
@@ -48,7 +51,7 @@
     for (DFNode *abs = abstract->first; abs != NULL; abs = abs->next)
         count++;
 
-    DFNode **conChildren = (DFNode **)malloc(count*sizeof(DFNode*));
+    DFNode **conChildren = (DFNode **)xmalloc(count*sizeof(DFNode*));
     count = 0;
 
     for (DFNode *abs = abstract->first; abs != NULL; abs = abs->next) {
diff --git a/DocFormats/core/src/common/DFBDT.h b/DocFormats/core/src/common/DFBDT.h
index 253049a..7393dae 100644
--- a/DocFormats/core/src/common/DFBDT.h
+++ b/DocFormats/core/src/common/DFBDT.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFBDT_h
 #define DocFormats_DFBDT_h
diff --git a/DocFormats/core/src/common/DFClassNames.h b/DocFormats/core/src/common/DFClassNames.h
index 914d96f..7cd07e1 100644
--- a/DocFormats/core/src/common/DFClassNames.h
+++ b/DocFormats/core/src/common/DFClassNames.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFClassNames_h
 #define DocFormats_DFClassNames_h
diff --git a/DocFormats/core/src/common/DFTable.c b/DocFormats/core/src/common/DFTable.c
index c99e6e1..1038f47 100644
--- a/DocFormats/core/src/common/DFTable.c
+++ b/DocFormats/core/src/common/DFTable.c
@@ -1,20 +1,24 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFTable.h"
 #include "DFDOM.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -35,7 +39,7 @@
 
 DFCell *DFCellNew(DFNode *element, unsigned int row, unsigned int col)
 {
-    DFCell *cell = (DFCell *)calloc(1,sizeof(DFCell));
+    DFCell *cell = (DFCell *)xcalloc(1,sizeof(DFCell));
     cell->retainCount = 1;
     cell->element = element;
     cell->row = row;
@@ -67,16 +71,16 @@
 
 DFTable *DFTableNew(unsigned int rows, unsigned int cols)
 {
-    DFTable *table = (DFTable *)calloc(1,sizeof(DFTable));
+    DFTable *table = (DFTable *)xcalloc(1,sizeof(DFTable));
     table->retainCount = 1;
     table->rows = rows;
     table->cols = cols;
-    table->rowElements = (DFNode **)calloc(table->rows,sizeof(DFNode *));
-    table->colWidths = (double *)calloc(table->cols,sizeof(double));
+    table->rowElements = (DFNode **)xcalloc(table->rows,sizeof(DFNode *));
+    table->colWidths = (double *)xcalloc(table->cols,sizeof(double));
 
-    table->cells = (DFCell ***)calloc(rows,sizeof(DFCell **));
+    table->cells = (DFCell ***)xcalloc(rows,sizeof(DFCell **));
     for (unsigned int r = 0; r < table->rows; r++)
-        table->cells[r] = (DFCell **)calloc(cols,sizeof(DFCell *));
+        table->cells[r] = (DFCell **)xcalloc(cols,sizeof(DFCell *));
 
     return table;
 }
diff --git a/DocFormats/core/src/common/DFTable.h b/DocFormats/core/src/common/DFTable.h
index f34a7b2..fff4f06 100644
--- a/DocFormats/core/src/common/DFTable.h
+++ b/DocFormats/core/src/common/DFTable.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFTable_h
 #define DocFormats_DFTable_h
diff --git a/DocFormats/core/src/css/CSS.c b/DocFormats/core/src/css/CSS.c
index f86b496..7f2bbf2 100644
--- a/DocFormats/core/src/css/CSS.c
+++ b/DocFormats/core/src/css/CSS.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "CSS.h"
 #include "CSSParser.h"
@@ -21,6 +24,7 @@
 #include "DFString.h"
 #include "DFCharacterSet.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <assert.h>
 #include <ctype.h>
 #include <stdlib.h>
@@ -81,7 +85,7 @@
 
 ContentPart *ContentPartNew(ContentPartType type, const char *value, const char *arg)
 {
-    ContentPart *part = (ContentPart *)calloc(1,sizeof(ContentPart));
+    ContentPart *part = (ContentPart *)xcalloc(1,sizeof(ContentPart));
     part->retainCount = 1;
     part->type = type;
     part->value = DFStrDup(value);
@@ -161,7 +165,7 @@
     DFHashTable *properties = CSSParserProperties(parser);
     CSSParserFree(parser);
     if (properties == NULL)
-        return DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+        return DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
     else
         return properties;
 }
@@ -186,7 +190,7 @@
         count++;
     }
     free(allKeys);
-    char *result = strdup(output->data);
+    char *result = xstrdup(output->data);
     DFBufferRelease(output);
     return result;
 }
@@ -220,31 +224,31 @@
         count++;
     switch (count) {
         case 1:
-            sides->top = strdup(tokens[0]);
-            sides->bottom = strdup(tokens[0]);
-            sides->left = strdup(tokens[0]);
-            sides->right = strdup(tokens[0]);
+            sides->top = xstrdup(tokens[0]);
+            sides->bottom = xstrdup(tokens[0]);
+            sides->left = xstrdup(tokens[0]);
+            sides->right = xstrdup(tokens[0]);
             ok = 1;
             break;
         case 2:
-            sides->top = strdup(tokens[0]);
-            sides->bottom = strdup(tokens[0]);
-            sides->left = strdup(tokens[1]);
-            sides->right = strdup(tokens[1]);
+            sides->top = xstrdup(tokens[0]);
+            sides->bottom = xstrdup(tokens[0]);
+            sides->left = xstrdup(tokens[1]);
+            sides->right = xstrdup(tokens[1]);
             ok = 1;
             break;
         case 3:
-            sides->top = strdup(tokens[0]);
-            sides->left = strdup(tokens[1]);
-            sides->right = strdup(tokens[1]);
-            sides->bottom = strdup(tokens[2]);
+            sides->top = xstrdup(tokens[0]);
+            sides->left = xstrdup(tokens[1]);
+            sides->right = xstrdup(tokens[1]);
+            sides->bottom = xstrdup(tokens[2]);
             ok = 1;
             break;
         case 4:
-            sides->top = strdup(tokens[0]);
-            sides->right = strdup(tokens[1]);
-            sides->bottom = strdup(tokens[2]);
-            sides->left = strdup(tokens[3]);
+            sides->top = xstrdup(tokens[0]);
+            sides->right = xstrdup(tokens[1]);
+            sides->bottom = xstrdup(tokens[2]);
+            sides->left = xstrdup(tokens[3]);
             ok = 1;
             break;
     }
@@ -575,7 +579,7 @@
 
 static DFHashTable *builtTextRules(DFHashTable *input)
 {
-    DFHashTable *result = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    DFHashTable *result = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
 
     const char **allSelectors = DFHashTableCopyKeys(input);
     for (int selIndex = 0; allSelectors[selIndex]; selIndex++) {
@@ -620,7 +624,7 @@
 
         DFArray *array = DFHashTableLookup(reverse,text);
         if (array == NULL) {
-            array = DFArrayNew((DFCopyFunction)strdup,free);
+            array = DFArrayNew((DFCopyFunction)xstrdup,free);
             DFHashTableAdd(reverse,text,array);
             DFArrayRelease(array);
         }
@@ -628,7 +632,7 @@
     }
     free(separateKeys);
 
-    DFHashTable *combined = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    DFHashTable *combined = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
     const char **reverseKeys = DFHashTableCopyKeys(reverse);
     for (int keyIndex = 0; reverseKeys[keyIndex]; keyIndex++) {
         const char *text = reverseKeys[keyIndex];
@@ -670,7 +674,7 @@
     free(allSelectors);
     DFHashTableRelease(separate);
     DFHashTableRelease(textRules);
-    char *result = strdup(output->data);
+    char *result = xstrdup(output->data);
     DFBufferRelease(output);
     return result;
 }
@@ -781,7 +785,7 @@
     }
 
     if (!includeHash && (result != NULL)) {
-        char *nohash = strdup(&result[1]);
+        char *nohash = xstrdup(&result[1]);
         free(result);
         result = nohash;
     }
@@ -796,7 +800,7 @@
     if (DFStringContainsWhitespace(input))
         return DFQuote(input);
     else
-        return strdup(input);
+        return xstrdup(input);
 }
 
 char *CSSDecodeFontFamily(const char *input)
@@ -1071,12 +1075,12 @@
         free(className);
     }
     else {
-        *result = strdup(elementName);
+        *result = xstrdup(elementName);
     }
 
     // Parse suffix
     // FIXME: ignore spaces at start?
-    *suffix = strdup(&cinput[pos]);
+    *suffix = xstrdup(&cinput[pos]);
 
     free(elementName);
 }
diff --git a/DocFormats/core/src/css/CSS.h b/DocFormats/core/src/css/CSS.h
index 2ff787e..ccd64e1 100644
--- a/DocFormats/core/src/css/CSS.h
+++ b/DocFormats/core/src/css/CSS.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_CSS_h
 #define DocFormats_CSS_h
diff --git a/DocFormats/core/src/css/CSSLength.c b/DocFormats/core/src/css/CSSLength.c
index 97e6824..71ebb90 100644
--- a/DocFormats/core/src/css/CSSLength.c
+++ b/DocFormats/core/src/css/CSSLength.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "CSSLength.h"
 #include "DFCommon.h"
diff --git a/DocFormats/core/src/css/CSSLength.h b/DocFormats/core/src/css/CSSLength.h
index d73d000..fb4eb50 100644
--- a/DocFormats/core/src/css/CSSLength.h
+++ b/DocFormats/core/src/css/CSSLength.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_CSSLength_h
 #define DocFormats_CSSLength_h
diff --git a/DocFormats/core/src/css/CSSParser.c b/DocFormats/core/src/css/CSSParser.c
index 5f6c546..b6fadfc 100644
--- a/DocFormats/core/src/css/CSSParser.c
+++ b/DocFormats/core/src/css/CSSParser.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "CSSParser.h"
 #include "CSS.h"
@@ -18,6 +21,7 @@
 #include "DFString.h"
 #include "DFCharacterSet.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
@@ -43,11 +47,11 @@
 
 CSSParser *CSSParserNew(const char *cinput)
 {
-    CSSParser *p = (CSSParser *)calloc(1,sizeof(CSSParser));
+    CSSParser *p = (CSSParser *)xcalloc(1,sizeof(CSSParser));
     if (cinput == NULL)
         cinput = "";
 
-    p->chars = strdup(cinput);
+    p->chars = xstrdup(cinput);
     p->length = strlen(cinput);
 
     return p;
@@ -206,7 +210,7 @@
 
 DFHashTable *CSSParserRules(CSSParser *p)
 {
-    DFHashTable *result = DFHashTableNew((DFCopyFunction)strdup,free);
+    DFHashTable *result = DFHashTableNew((DFCopyFunction)xstrdup,free);
     while (p->pos < p->length) {
         size_t start = p->pos;
         int invalid = 0;
@@ -241,7 +245,7 @@
 
 DFArray *CSSParserSelectors(CSSParser *p)
 {
-    DFArray *result = DFArrayNew((DFCopyFunction)strdup,free);
+    DFArray *result = DFArrayNew((DFCopyFunction)xstrdup,free);
     while (p->pos < p->length) {
         size_t start = p->pos;
         int invalid = 0;
@@ -261,7 +265,7 @@
 
 DFHashTable *CSSParserProperties(CSSParser *p)
 {
-    DFHashTable *result = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    DFHashTable *result = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
     while (p->pos < p->length) {
         size_t start = p->pos;
         int invalid = 0;
diff --git a/DocFormats/core/src/css/CSSParser.h b/DocFormats/core/src/css/CSSParser.h
index 1491cf0..d1adf5c 100644
--- a/DocFormats/core/src/css/CSSParser.h
+++ b/DocFormats/core/src/css/CSSParser.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_CSSParser_h
 #define DocFormats_CSSParser_h
diff --git a/DocFormats/core/src/css/CSSProperties.c b/DocFormats/core/src/css/CSSProperties.c
index e3f4973..5d96459 100644
--- a/DocFormats/core/src/css/CSSProperties.c
+++ b/DocFormats/core/src/css/CSSProperties.c
@@ -1,22 +1,26 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "CSSProperties.h"
 #include "CSS.h"
 #include "DFString.h"
 #include "DFHashTable.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -149,9 +153,9 @@
     DFHashTable *extra = CSSParseProperties(string);
     CSSExpandProperties(extra);
 
-    CSSProperties *result = (CSSProperties *)calloc(1,sizeof(CSSProperties));
+    CSSProperties *result = (CSSProperties *)xcalloc(1,sizeof(CSSProperties));
     result->retainCount = 1;
-    result->hashTable = DFHashTableNew((DFCopyFunction)strdup,free);
+    result->hashTable = DFHashTableNew((DFCopyFunction)xstrdup,free);
     const char **names = DFHashTableCopyKeys(orig->hashTable);
     for (int i = 0; names[i]; i++) {
         const char *value = DFHashTableLookup(orig->hashTable,names[i]);
@@ -173,10 +177,10 @@
 
 CSSProperties *CSSPropertiesNewWithRaw(DFHashTable *raw)
 {
-    CSSProperties *result = (CSSProperties *)calloc(1,sizeof(CSSProperties));
+    CSSProperties *result = (CSSProperties *)xcalloc(1,sizeof(CSSProperties));
     result->retainCount = 1;
 
-    result->hashTable = DFHashTableNew((DFCopyFunction)strdup,free);
+    result->hashTable = DFHashTableNew((DFCopyFunction)xstrdup,free);
     if (raw != NULL)
         CSSPropertiesUpdateFromRaw(result,raw);
 
diff --git a/DocFormats/core/src/css/CSSProperties.h b/DocFormats/core/src/css/CSSProperties.h
index 22de4fd..0ea4eab 100644
--- a/DocFormats/core/src/css/CSSProperties.h
+++ b/DocFormats/core/src/css/CSSProperties.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_CSSProperties_h
 #define DocFormats_CSSProperties_h
diff --git a/DocFormats/core/src/css/CSSSelector.c b/DocFormats/core/src/css/CSSSelector.c
index 52220be..ec17e3e 100644
--- a/DocFormats/core/src/css/CSSSelector.c
+++ b/DocFormats/core/src/css/CSSSelector.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "CSSSelector.h"
@@ -62,7 +65,7 @@
     if (className != NULL)
         return DFFormatString("%s.%s",elementName,className);
     else
-        return strdup(elementName);
+        return xstrdup(elementName);
 }
 
 char *CSSMakeTagSelector(Tag tag, const char *className)
@@ -111,9 +114,9 @@
         return NULL;
     int dotPos = findDotPos(selector);
     if (dotPos < 0)
-        return strdup(selector);
+        return xstrdup(selector);
 
-    char *result = (char *)malloc(dotPos+1);
+    char *result = (char *)xmalloc(dotPos+1);
     memcpy(result,selector,dotPos);
     result[dotPos] = '\0';
     return result;
@@ -128,7 +131,7 @@
         return NULL;
     int start = dotPos + 1;
     int len = (int)strlen(selector) - start;
-    char *result = (char *)malloc(len+1);
+    char *result = (char *)xmalloc(len+1);
     memcpy(result,&selector[start],len);
     result[len] = '\0';
     return result;
diff --git a/DocFormats/core/src/css/CSSSelector.h b/DocFormats/core/src/css/CSSSelector.h
index 6e9c283..4151c41 100644
--- a/DocFormats/core/src/css/CSSSelector.h
+++ b/DocFormats/core/src/css/CSSSelector.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_CSSSelector_h
 #define DocFormats_CSSSelector_h
diff --git a/DocFormats/core/src/css/CSSSheet.c b/DocFormats/core/src/css/CSSSheet.c
index 151201f..8f8cdcf 100644
--- a/DocFormats/core/src/css/CSSSheet.c
+++ b/DocFormats/core/src/css/CSSSheet.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "CSSSheet.h"
 #include "CSS.h"
@@ -22,6 +25,7 @@
 #include "DFHashTable.h"
 #include "DFBuffer.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
@@ -40,7 +44,7 @@
 
 CSSSheet *CSSSheetNew(void)
 {
-    CSSSheet *sheet = (CSSSheet *)calloc(1,sizeof(CSSSheet));
+    CSSSheet *sheet = (CSSSheet *)xcalloc(1,sizeof(CSSSheet));
     sheet->retainCount = 1;
     sheet->_styles = DFHashTableNew((DFCopyFunction)CSSStyleRetain,(DFFreeFunction)CSSStyleRelease);
     sheet->_defaultStyles = DFHashTableNew((DFCopyFunction)CSSStyleRetain,(DFFreeFunction)CSSStyleRelease);
@@ -107,7 +111,7 @@
     // FIXME: Need tests for parent cycles
     CSSStyle *ancestor = orig;
     CSSStyle *result = CSSStyleNew("temp");
-    DFHashTable *visited = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    DFHashTable *visited = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
     const char **allSuffixes = NULL;
     while (1) {
         free(allSuffixes);
@@ -157,7 +161,7 @@
             free(escapedClassName);
         }
         else {
-            baseSelector = strdup(elementName);
+            baseSelector = xstrdup(elementName);
         }
 
         CSSStyle *flattenedStyle = CSSSheetFlattenedStyle(sheet,origStyle);
@@ -221,7 +225,7 @@
         free(sortedSuffixes);
     }
     free(allSelectors);
-    char *str = strdup(result->data);
+    char *str = xstrdup(result->data);
     DFBufferRelease(result);
     return str;
 }
@@ -233,7 +237,7 @@
     for (int i = 0; allSelectors[i]; i++) {
         const char *selector = allSelectors[i];
         CSSStyle *style = CSSSheetLookupSelector(sheet,selector,0,0);
-        DFHashTable *visited = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+        DFHashTable *visited = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
         int depth = 0;
 
         while (style != NULL) {
@@ -264,7 +268,7 @@
             depth++;
 
         while (DFArrayCount(selectorsByDepth) < depth+1) {
-            DFArray *array = DFArrayNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+            DFArray *array = DFArrayNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
             DFArrayAppend(selectorsByDepth,array);
             DFArrayRelease(array);
         }
@@ -274,7 +278,7 @@
     }
     free(allSelectors);
 
-    DFArray *sortedSelectors = DFArrayNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    DFArray *sortedSelectors = DFArrayNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
     for (size_t i = DFArrayCount(selectorsByDepth); i > 0; i--) {
         DFArray *atDepth = DFArrayItemAt(selectorsByDepth,i-1);
         for (size_t j = 0; j < DFArrayCount(atDepth); j++)
@@ -349,7 +353,7 @@
         if (!strncmp(constSelector,".",1))
             selector = DFFormatString("p%s",constSelector); // FIXME: Not covered by tests
         else
-            selector = strdup(constSelector);
+            selector = xstrdup(constSelector);
 
         DFHashTable *raw = DFHashTableLookup(rules,constSelector);
         char *baseId = NULL;
@@ -491,7 +495,7 @@
         CSSStyle *style = CSSSheetLookupSelector(sheet,allSelectors[i],0,0);
         if (style->headingLevel > 0) {
             int headingLevel = style->headingLevel;
-            StyleList *item = (StyleList *)calloc(1,sizeof(StyleList));
+            StyleList *item = (StyleList *)xcalloc(1,sizeof(StyleList));
             item->style = CSSStyleRetain(style);
             item->next = DFHashTableLookupInt(stylesByHeadingLevel,headingLevel);
             DFHashTableAddInt(stylesByHeadingLevel,headingLevel,item);
diff --git a/DocFormats/core/src/css/CSSSheet.h b/DocFormats/core/src/css/CSSSheet.h
index 2d71a91..1ff03e8 100644
--- a/DocFormats/core/src/css/CSSSheet.h
+++ b/DocFormats/core/src/css/CSSSheet.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_CSSSheet_h
 #define DocFormats_CSSSheet_h
diff --git a/DocFormats/core/src/css/CSSStyle.c b/DocFormats/core/src/css/CSSStyle.c
index 73c9445..8b9b8a4 100644
--- a/DocFormats/core/src/css/CSSStyle.c
+++ b/DocFormats/core/src/css/CSSStyle.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "CSSStyle.h"
 #include "CSSSheet.h"
@@ -21,6 +24,7 @@
 #include "DFHashTable.h"
 #include "DFString.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -54,7 +58,7 @@
 
 CSSStyle *CSSStyleNew(const char *selector)
 {
-    CSSStyle *style = (CSSStyle *)calloc(1,sizeof(CSSStyle));
+    CSSStyle *style = (CSSStyle *)xcalloc(1,sizeof(CSSStyle));
     style->retainCount = 1;
     CSSStyleSetSelector(style,selector);
     style->rules = DFHashTableNew((DFCopyFunction)CSSPropertiesRetain,(DFFreeFunction)CSSPropertiesRelease);
@@ -92,7 +96,7 @@
 void CSSStyleSetSelector(CSSStyle *style, const char *newSelector)
 {
     // Take a copy of newSelector first, just in case it's one of the values we're about to free
-    char *selector = strdup(newSelector);
+    char *selector = xstrdup(newSelector);
 
     free(style->selector);
     free(style->elementName);
diff --git a/DocFormats/core/src/css/CSSStyle.h b/DocFormats/core/src/css/CSSStyle.h
index 8059ec4..ae1ff4e 100644
--- a/DocFormats/core/src/css/CSSStyle.h
+++ b/DocFormats/core/src/css/CSSStyle.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_CSSStyle_h
 #define DocFormats_CSSStyle_h
diff --git a/DocFormats/core/src/css/CSSSyntax.c b/DocFormats/core/src/css/CSSSyntax.c
index 9147d44..dfab238 100644
--- a/DocFormats/core/src/css/CSSSyntax.c
+++ b/DocFormats/core/src/css/CSSSyntax.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "CSSSyntax.h"
 #include "DFCommon.h"
diff --git a/DocFormats/core/src/css/CSSSyntax.h b/DocFormats/core/src/css/CSSSyntax.h
index 09e8fd1..945f118 100644
--- a/DocFormats/core/src/css/CSSSyntax.h
+++ b/DocFormats/core/src/css/CSSSyntax.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_CSSSyntax_h
 #define DocFormats_CSSSyntax_h
diff --git a/DocFormats/core/src/html/DFHTDocument.c b/DocFormats/core/src/html/DFHTDocument.c
index 6d6c3f0..70aad45 100644
--- a/DocFormats/core/src/html/DFHTDocument.c
+++ b/DocFormats/core/src/html/DFHTDocument.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFHTDocument.h"
@@ -103,7 +106,7 @@
 
 DFHTDocument *DFHTDocumentNew()
 {
-    DFHTDocument *htd = (DFHTDocument *)calloc(1,sizeof(DFHTDocument));
+    DFHTDocument *htd = (DFHTDocument *)xcalloc(1,sizeof(DFHTDocument));
     htd->doc = tidyCreate();
     tidyBufInit(&htd->errbuf);
     tidySetErrorBuffer(htd->doc,&htd->errbuf);
diff --git a/DocFormats/core/src/html/DFHTDocument.h b/DocFormats/core/src/html/DFHTDocument.h
index 6b5860d..c5aac49 100644
--- a/DocFormats/core/src/html/DFHTDocument.h
+++ b/DocFormats/core/src/html/DFHTDocument.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFHTDocument_h
 #define DocFormats_DFHTDocument_h
diff --git a/DocFormats/core/src/html/DFHTML.c b/DocFormats/core/src/html/DFHTML.c
index 0f2a348..b6538ee 100644
--- a/DocFormats/core/src/html/DFHTML.c
+++ b/DocFormats/core/src/html/DFHTML.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFHTML.h"
@@ -68,10 +71,10 @@
 {
     DFNode *head = DFChildWithTag(doc->root,HTML_HEAD);
     if (head == NULL)
-        return strdup("");;
+        return xstrdup("");;
     DFNode *style = DFChildWithTag(head,HTML_STYLE);
     if (style == NULL)
-        return strdup("");
+        return xstrdup("");
     return DFNodeTextToString(style);
 }
 
@@ -193,7 +196,7 @@
 
 static char *indentString(int depth)
 {
-    char *str = (char *)malloc(1+depth*2+1);
+    char *str = (char *)xmalloc(1+depth*2+1);
     str[0] = '\n';
     memset(&str[1],' ',depth*2);
     str[1+depth*2] = '\0';
@@ -359,6 +362,56 @@
     return (strlen(str) == 7) && (str[0] == '#') && isRRGGBB(&str[1]);
 }
 
+const char *HTMLMetaGet(DFDocument *htmlDoc, const char *name)
+{
+    assert(htmlDoc->root != NULL);
+    assert(htmlDoc->root->tag == HTML_HTML);
+    DFNode *head = DFChildWithTag(htmlDoc->root,HTML_HEAD);
+    if (head == NULL)
+        return NULL;
+    for (DFNode *meta = head->first; meta != NULL; meta = meta->next) {
+        if ((meta->tag == HTML_META) && DFStringEquals(DFGetAttribute(meta,HTML_NAME),name))
+            return DFGetAttribute(meta,HTML_CONTENT);
+    }
+    return NULL;
+}
+
+void HTMLMetaSet(DFDocument *htmlDoc, const char *name, const char *content)
+{
+    assert(htmlDoc->root != NULL);
+    assert(htmlDoc->root->tag == HTML_HTML);
+    DFNode *head = DFChildWithTag(htmlDoc->root,HTML_HEAD);
+    if (head == NULL) {
+        head = DFCreateElement(htmlDoc,HTML_HEAD);
+        DFNode *body = DFChildWithTag(htmlDoc->root,HTML_BODY);
+        DFInsertBefore(htmlDoc->root,head,body);
+    }
+    for (DFNode *meta = head->first; meta != NULL; meta = meta->next) {
+        if ((meta->tag == HTML_META) && DFStringEquals(DFGetAttribute(meta,HTML_NAME),name)) {
+            DFSetAttribute(meta,HTML_CONTENT,content);
+            return;
+        }
+    }
+    DFNode *meta = DFCreateChildElement(head,HTML_META);
+    DFSetAttribute(meta,HTML_NAME,name);
+    DFSetAttribute(meta,HTML_CONTENT,content);
+}
+
+void HTMLMetaRemove(DFDocument *htmlDoc, const char *name)
+{
+    assert(htmlDoc->root != NULL);
+    assert(htmlDoc->root->tag == HTML_HTML);
+    DFNode *head = DFChildWithTag(htmlDoc->root,HTML_HEAD);
+    if (head == NULL)
+        return;;
+    DFNode *next;
+    for (DFNode *meta = head->first; meta != NULL; meta = next) {
+        next = meta->next;
+        if ((meta->tag == HTML_META) && DFStringEquals(DFGetAttribute(meta,HTML_NAME),name))
+            DFRemoveNode(meta);
+    }
+}
+
 DFDocument *DFParseHTMLString(const char *str, int removeSpecial, DFError **error)
 {
     DFHTDocument *htdoc = DFHTDocumentNew();
diff --git a/DocFormats/core/src/html/DFHTML.h b/DocFormats/core/src/html/DFHTML.h
index a4a5bab..81c9592 100644
--- a/DocFormats/core/src/html/DFHTML.h
+++ b/DocFormats/core/src/html/DFHTML.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFHTML_h
 #define DocFormats_DFHTML_h
@@ -47,6 +50,10 @@
 int isRRGGBB(const char *str);
 int isHashRRGGBB(const char *str);
 
+const char *HTMLMetaGet(DFDocument *htmlDoc, const char *name);
+void HTMLMetaSet(DFDocument *htmlDoc, const char *name, const char *content);
+void HTMLMetaRemove(DFDocument *htmlDoc, const char *name);
+
 DFDocument *DFParseHTMLString(const char *str, int removeSpecial, DFError **error);
 DFDocument *DFParseHTMLFile(const char *filename, int removeSpecial, DFError **error);
 const char **DFHTMLGetImages(DFDocument *htmlDoc);
diff --git a/DocFormats/core/src/html/DFHTMLNormalization.c b/DocFormats/core/src/html/DFHTMLNormalization.c
index 36404a5..5455611 100644
--- a/DocFormats/core/src/html/DFHTMLNormalization.c
+++ b/DocFormats/core/src/html/DFHTMLNormalization.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFHTMLNormalization.h"
@@ -120,7 +123,7 @@
 static void findLeafNodes(DFNode *node, int depth, DFArray *leafEntries)
 {
     if (node->first == NULL) {
-        LeafEntry *entry = (LeafEntry *)calloc(1,sizeof(LeafEntry));
+        LeafEntry *entry = (LeafEntry *)xcalloc(1,sizeof(LeafEntry));
         entry->node = node;
         entry->depth = depth;
         DFArrayAppend(leafEntries,entry);
@@ -148,7 +151,7 @@
 
         uint32_t *oldChars = DFUTF8To32(entry->node->value);
         size_t oldLen = DFUTF32Length(oldChars);
-        uint32_t *newChars = (uint32_t *)malloc((oldLen+1)*sizeof(uint32_t));
+        uint32_t *newChars = (uint32_t *)xmalloc((oldLen+1)*sizeof(uint32_t));
         size_t newLen = 0;
         int haveSpace = 0;
 
@@ -610,7 +613,7 @@
 
 static DFHashTable *extractInlineProperties(DFNode *paragraph)
 {
-    DFHashTable *inlineProperties = DFHashTableNew((DFCopyFunction)strdup,free);
+    DFHashTable *inlineProperties = DFHashTableNew((DFCopyFunction)xstrdup,free);
     const char *paraCSSText = DFGetAttribute(paragraph,HTML_STYLE);
     CSSProperties *paraProperties = CSSPropertiesNewWithString(paraCSSText);
     const char **allNames = CSSPropertiesCopyNames(paraProperties);
diff --git a/DocFormats/core/src/html/DFHTMLNormalization.h b/DocFormats/core/src/html/DFHTMLNormalization.h
index b899903..2565fa4 100644
--- a/DocFormats/core/src/html/DFHTMLNormalization.h
+++ b/DocFormats/core/src/html/DFHTMLNormalization.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFHTMLNormalization_h
 #define DocFormats_DFHTMLNormalization_h
diff --git a/DocFormats/core/src/html/DFHTMLTables.c b/DocFormats/core/src/html/DFHTMLTables.c
index fa58b2a..5863676 100644
--- a/DocFormats/core/src/html/DFHTMLTables.c
+++ b/DocFormats/core/src/html/DFHTMLTables.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFHTMLTables.h"
 #include "DFTable.h"
@@ -18,6 +21,7 @@
 #include "DFString.h"
 #include "CSSLength.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <assert.h>
 #include <stdlib.h>
 
@@ -55,7 +59,7 @@
     for (DFNode *tableChild = table->first; tableChild != NULL; tableChild = tableChild->next) {
         switch (tableChild->tag) {
             case HTML_TR: {
-                RowList *item = (RowList *)calloc(1,sizeof(RowList));
+                RowList *item = (RowList *)xcalloc(1,sizeof(RowList));
                 item->rowNode = tableChild;
                 *listPtr = item;
                 listPtr = &item->next;
@@ -66,7 +70,7 @@
             case HTML_TFOOT: {
                 for (DFNode *partChild = tableChild->first; partChild != NULL; partChild = partChild->next) {
                     if (partChild->tag == HTML_TR) {
-                        RowList *item = (RowList *)calloc(1,sizeof(RowList));
+                        RowList *item = (RowList *)xcalloc(1,sizeof(RowList));
                         item->rowNode = partChild;
                         *listPtr = item;
                         listPtr = &item->next;
diff --git a/DocFormats/core/src/html/DFHTMLTables.h b/DocFormats/core/src/html/DFHTMLTables.h
index 9291de7..18bfda3 100644
--- a/DocFormats/core/src/html/DFHTMLTables.h
+++ b/DocFormats/core/src/html/DFHTMLTables.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFHTMLTables_h
 #define DocFormats_DFHTMLTables_h
diff --git a/DocFormats/core/src/html/DFTidyHelper.c b/DocFormats/core/src/html/DFTidyHelper.c
index f2f2303..af9689b 100644
--- a/DocFormats/core/src/html/DFTidyHelper.c
+++ b/DocFormats/core/src/html/DFTidyHelper.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFTidyHelper.h"
@@ -25,7 +28,7 @@
     tidyBufInit(&buf);
     tidyNodeGetValue(tdoc,tnode,&buf);
 
-    char *str = (char *)malloc(buf.size+1);
+    char *str = (char *)xmalloc(buf.size+1);
     memcpy(str,buf.bp,buf.size);
     str[buf.size] = '\0';
 
diff --git a/DocFormats/core/src/html/DFTidyHelper.h b/DocFormats/core/src/html/DFTidyHelper.h
index 6ed6c81..df5075c 100644
--- a/DocFormats/core/src/html/DFTidyHelper.h
+++ b/DocFormats/core/src/html/DFTidyHelper.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFTidyHelper_h
 #define DocFormats_DFTidyHelper_h
diff --git a/DocFormats/core/src/html/DFTidyWrapper.c b/DocFormats/core/src/html/DFTidyWrapper.c
index 72fe583..7b81ed6 100644
--- a/DocFormats/core/src/html/DFTidyWrapper.c
+++ b/DocFormats/core/src/html/DFTidyWrapper.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFTidyWrapper.h"
diff --git a/DocFormats/core/src/html/DFTidyWrapper.h b/DocFormats/core/src/html/DFTidyWrapper.h
index 12ac589..4cb6cfb 100644
--- a/DocFormats/core/src/html/DFTidyWrapper.h
+++ b/DocFormats/core/src/html/DFTidyWrapper.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFTidyWrapper_h
 #define DocFormats_DFTidyWrapper_h
diff --git a/DocFormats/core/src/lib/DFAllocator.c b/DocFormats/core/src/lib/DFAllocator.c
index 722fe0a..f12a72d 100644
--- a/DocFormats/core/src/lib/DFAllocator.c
+++ b/DocFormats/core/src/lib/DFAllocator.c
@@ -1,17 +1,21 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
+#include "DFPlatform.h"
 #include "DFAllocator.h"
 #include "DFCommon.h"
 #include <assert.h>
@@ -34,8 +38,8 @@
 DFAllocator *DFAllocatorNew(void)
 {
     size_t initialSize = 1;
-    DFAllocator *alc = (DFAllocator *)malloc(sizeof(DFAllocator));
-    alc->blocks = (DFAllocatorBlock *)malloc(sizeof(DFAllocatorBlock)+initialSize);
+    DFAllocator *alc = (DFAllocator *)xmalloc(sizeof(DFAllocator));
+    alc->blocks = (DFAllocatorBlock *)xmalloc(sizeof(DFAllocatorBlock)+initialSize);
     alc->blocks->next = NULL;
     alc->blocks->used = 0;
     alc->blocks->size = initialSize;
@@ -63,7 +67,7 @@
         size_t newSize = block->size*2;
         while (size > newSize)
             newSize *= 2;
-        block = (DFAllocatorBlock *)malloc(sizeof(DFAllocatorBlock)+newSize);
+        block = (DFAllocatorBlock *)xmalloc(sizeof(DFAllocatorBlock)+newSize);
         block->used = 0;
         block->size = newSize;
         block->next = alc->blocks;
@@ -73,6 +77,6 @@
     char *mem = block->mem + block->used;
     block->used += size;
     assert(block->used <= block->size);
-    assert((((unsigned long long)mem) % 8) == 0);
+    assert((((unsigned long)mem) % 8) == 0);
     return mem;
 }
diff --git a/DocFormats/core/src/lib/DFAllocator.h b/DocFormats/core/src/lib/DFAllocator.h
index 94f40eb..d95cf5d 100644
--- a/DocFormats/core/src/lib/DFAllocator.h
+++ b/DocFormats/core/src/lib/DFAllocator.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFAllocator_h
 #define DocFormats_DFAllocator_h
diff --git a/DocFormats/core/src/lib/DFArray.c b/DocFormats/core/src/lib/DFArray.c
index 28e1317..053a754 100644
--- a/DocFormats/core/src/lib/DFArray.c
+++ b/DocFormats/core/src/lib/DFArray.c
@@ -1,17 +1,21 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
+#include "DFPlatform.h"
 #include "DFArray.h"
 #include "DFCommon.h"
 #include <assert.h>
@@ -29,7 +33,7 @@
 
 DFArray *DFArrayNew(DFCopyFunction copy, DFFreeFunction free)
 {
-    DFArray *array = (DFArray *)calloc(1,sizeof(DFArray));
+    DFArray *array = (DFArray *)xcalloc(1,sizeof(DFArray));
     array->retainCount = 1;
     array->copyFun = copy;
     array->freeFun = free;
@@ -86,7 +90,7 @@
             array->alloc = 1;
         else
             array->alloc *= 2;
-        array->items = (void **)realloc(array->items,array->alloc*sizeof(void *));
+        array->items = (void **)xrealloc(array->items,array->alloc*sizeof(void *));
     }
     array->items[array->count++] = item;
 }
@@ -127,7 +131,7 @@
 
 void DFSort(void *base, size_t nel, size_t width, void *thunk, int (*compar)(void *, const void *, const void *))
 {
-    void *work = malloc(nel*width);
+    void *work = xmalloc(nel*width);
     DFSortInternal(base,nel,width,thunk,compar,work);
     free(work);
 }
diff --git a/DocFormats/core/src/lib/DFArray.h b/DocFormats/core/src/lib/DFArray.h
index 18f09f9..7996c5e 100644
--- a/DocFormats/core/src/lib/DFArray.h
+++ b/DocFormats/core/src/lib/DFArray.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFArray_h
 #define DocFormats_DFArray_h
diff --git a/DocFormats/core/src/lib/DFBuffer.c b/DocFormats/core/src/lib/DFBuffer.c
index 92c7a02..e79929f 100644
--- a/DocFormats/core/src/lib/DFBuffer.c
+++ b/DocFormats/core/src/lib/DFBuffer.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFBuffer.h"
@@ -30,11 +33,11 @@
 
 DFBuffer *DFBufferNew(void)
 {
-    DFBuffer *buf = (DFBuffer *)calloc(1,sizeof(DFBuffer));
+    DFBuffer *buf = (DFBuffer *)xcalloc(1,sizeof(DFBuffer));
     buf->retainCount = 1;
     buf->alloc = 1;
     buf->len = 0;
-    buf->data = (char *)malloc(buf->alloc*sizeof(char));
+    buf->data = (char *)xmalloc(buf->alloc*sizeof(char));
     buf->data[0] = '\0';
     return buf;
 }
@@ -65,7 +68,7 @@
     if (buf->alloc < want) {
         while (buf->alloc < want)
             buf->alloc *= 2;
-        buf->data = (char *)realloc(buf->data,buf->alloc);
+        buf->data = (char *)xrealloc(buf->data,buf->alloc);
     }
 }
 
@@ -191,7 +194,7 @@
     }
     if ((input->len % 40) != 0)
         DFBufferAppendChar(charBuf,'\n');
-    char *result = strdup(charBuf->data);
+    char *result = xstrdup(charBuf->data);
 
     DFBufferRelease(charBuf);
     return result;
diff --git a/DocFormats/core/src/lib/DFBuffer.h b/DocFormats/core/src/lib/DFBuffer.h
index 5103003..08aa204 100644
--- a/DocFormats/core/src/lib/DFBuffer.h
+++ b/DocFormats/core/src/lib/DFBuffer.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFBuffer_h
 #define DocFormats_DFBuffer_h
diff --git a/DocFormats/core/src/lib/DFCallback.c b/DocFormats/core/src/lib/DFCallback.c
index 5d5ab4f..d48e24d 100644
--- a/DocFormats/core/src/lib/DFCallback.c
+++ b/DocFormats/core/src/lib/DFCallback.c
@@ -1,25 +1,29 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFCallback.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <assert.h>
 #include <stdlib.h>
 
 void DFCallbackAdd(DFCallback **list, DFCallbackFunction fun, void *ctx)
 {
-    DFCallback *item = (DFCallback *)calloc(1,sizeof(DFCallback));
+    DFCallback *item = (DFCallback *)xcalloc(1,sizeof(DFCallback));
     item->fun = fun;
     item->ctx = ctx;
     item->next = *list;
diff --git a/DocFormats/core/src/lib/DFCallback.h b/DocFormats/core/src/lib/DFCallback.h
index 58db7fe..bf72a31 100644
--- a/DocFormats/core/src/lib/DFCallback.h
+++ b/DocFormats/core/src/lib/DFCallback.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFCallback_h
 #define DocFormats_DFCallback_h
diff --git a/DocFormats/core/src/lib/DFCharacterSet.c b/DocFormats/core/src/lib/DFCharacterSet.c
index b9e72dc..bf19476 100644
--- a/DocFormats/core/src/lib/DFCharacterSet.c
+++ b/DocFormats/core/src/lib/DFCharacterSet.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFCharacterSet.h"
 #include "DFCommon.h"
diff --git a/DocFormats/core/src/lib/DFCharacterSet.h b/DocFormats/core/src/lib/DFCharacterSet.h
index 534b850..a0e92f5 100644
--- a/DocFormats/core/src/lib/DFCharacterSet.h
+++ b/DocFormats/core/src/lib/DFCharacterSet.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFCharacterSet_h
 #define DocFormats_DFCharacterSet_h
diff --git a/DocFormats/core/src/lib/DFError.c b/DocFormats/core/src/lib/DFError.c
index 4eb19dd..4a716e3 100644
--- a/DocFormats/core/src/lib/DFError.c
+++ b/DocFormats/core/src/lib/DFError.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include <DocFormats/DFError.h>
@@ -41,7 +44,7 @@
     size_t nchars = vsnprintf(NULL,0,format,ap2);
     va_end(ap2);
 
-    char *message = (char *)malloc(nchars+1);
+    char *message = (char *)xmalloc(nchars+1);
 
     va_copy(ap2,ap);
     vsnprintf(message,nchars+1,format,ap2);
@@ -54,7 +57,7 @@
     }
     else {
         // Error object does not exist; create a new one
-        (*error) = (DFError *)calloc(1,sizeof(DFError));
+        (*error) = (DFError *)xcalloc(1,sizeof(DFError));
         (*error)->retainCount = 1;
         (*error)->message = message;
     }
diff --git a/DocFormats/core/src/lib/DFFilesystem.c b/DocFormats/core/src/lib/DFFilesystem.c
index 66c8a79..6c1a1bc 100644
--- a/DocFormats/core/src/lib/DFFilesystem.c
+++ b/DocFormats/core/src/lib/DFFilesystem.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFFilesystem.h"
@@ -19,7 +22,6 @@
 #include "DFBuffer.h"
 #include <DocFormats/DFError.h>
 #include "DFCharacterSet.h"
-#include "DFPlatform.h"
 #include "DFCommon.h"
 #include <assert.h>
 #include <errno.h>
@@ -174,7 +176,7 @@
 
 static DFArray *arrayFromDirEntryList(DFDirEntryList *list)
 {
-    DFArray *array = DFArrayNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    DFArray *array = DFArrayNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
     for (DFDirEntryList *l = list; l != NULL; l = l->next)
         DFArrayAppend(array,l->name);
     return array;
@@ -221,10 +223,10 @@
     size_t pos = len;
     while (1) {
         if (pos == 0)
-            return strdup("");
+            return xstrdup("");
         if (path[pos-1] == '/') {
             if (pos == 1)
-                return strdup("/");
+                return xstrdup("/");
             else
                 return DFSubstring(path,0,pos-1);
         }
@@ -261,9 +263,9 @@
     size_t pos = len;
     while (1) {
         if (pos == 0)
-            return strdup("");
+            return xstrdup("");
         if (path[pos-1] == '/')
-            return strdup("");
+            return xstrdup("");
         if (path[pos-1] == '.')
             return DFSubstring(path,pos,len);
         pos--;
@@ -277,7 +279,7 @@
         len--;
 
     if (!strcmp(path,"/"))
-        return strdup("/");;
+        return xstrdup("/");;
 
     size_t pos = len;
     while (1) {
@@ -294,7 +296,7 @@
 char *DFPathNormalize(const char *path)
 {
     size_t len = strlen(path);
-    char *result = (char *)malloc(len+1);
+    char *result = (char *)xmalloc(len+1);
     size_t outpos = 0;
     for (size_t pos = 0; pos < len; pos++) {
         if ((path[pos] != '/') || (pos == 0) || (path[pos-1] != '/'))
@@ -307,11 +309,11 @@
 char *DFPathResolveAbsolute(const char *rawBase, const char *relative)
 {
     if (relative[0] == '/')
-        return strdup(relative);
+        return xstrdup(relative);
 
     char *base;
     if (rawBase[0] == '/') {
-        base = strdup(rawBase);
+        base = xstrdup(rawBase);
     }
     else {
         char cwd[4096];
@@ -319,7 +321,7 @@
         base = DFFormatString("%s/%s",cwd,rawBase);
     }
 
-    char *baseDirectory = DFStringHasSuffix(base,"/") ? strdup(base) : DFPathDirName(base);
+    char *baseDirectory = DFStringHasSuffix(base,"/") ? xstrdup(base) : DFPathDirName(base);
 
     DFBuffer *path = DFBufferNew();
     DFBufferAppendString(path,baseDirectory);
@@ -371,7 +373,7 @@
 char *DFRemovePercentEncoding(const char *encoded)
 {
     size_t inlen = strlen(encoded);
-    char *output = (char *)malloc(inlen+1);
+    char *output = (char *)xmalloc(inlen+1);
     size_t outpos = 0;
     for (size_t inpos = 0; inpos < inlen; inpos++) {
         char ch = encoded[inpos];
diff --git a/DocFormats/core/src/lib/DFFilesystem.h b/DocFormats/core/src/lib/DFFilesystem.h
index e3e2869..3754dd7 100644
--- a/DocFormats/core/src/lib/DFFilesystem.h
+++ b/DocFormats/core/src/lib/DFFilesystem.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFUtil_h
 #define DocFormats_DFUtil_h
diff --git a/DocFormats/core/src/lib/DFHashTable.c b/DocFormats/core/src/lib/DFHashTable.c
index 6a1cfe8..5385c3e 100644
--- a/DocFormats/core/src/lib/DFHashTable.c
+++ b/DocFormats/core/src/lib/DFHashTable.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFHashTable.h"
@@ -44,10 +47,10 @@
 
 DFHashTable *DFHashTableNew2(DFCopyFunction copy, DFFreeFunction free, int binsCount)
 {
-    DFHashTable *table = (DFHashTable *)calloc(1,sizeof(DFHashTable));
+    DFHashTable *table = (DFHashTable *)xcalloc(1,sizeof(DFHashTable));
     table->retainCount = 1;
     table->binsCount = binsCount;
-    table->bins = (DFHashEntry **)calloc(1,table->binsCount*sizeof(DFHashEntry *));
+    table->bins = (DFHashEntry **)xcalloc(1,table->binsCount*sizeof(DFHashEntry *));
     table->copy = copy;
     table->free = free;
     return table;
@@ -130,7 +133,7 @@
             numBytes += strlen(entry->key)+1;
     }
 
-    void *mem = malloc(numBytes);
+    void *mem = xmalloc(numBytes);
     char **pointers = mem;
     char *storage = (char *)mem + (count+1)*sizeof(char *);
 
@@ -205,7 +208,7 @@
     }
     else {
         size_t len = strlen(key);
-        DFHashEntry *entry = (DFHashEntry *)malloc(sizeof(DFHashEntry)+len*sizeof(char)+1);
+        DFHashEntry *entry = (DFHashEntry *)xmalloc(sizeof(DFHashEntry)+len*sizeof(char)+1);
         entry->value = value;
         entry->hash = hash;
         memcpy(&entry->key[0],key,len);
diff --git a/DocFormats/core/src/lib/DFHashTable.h b/DocFormats/core/src/lib/DFHashTable.h
index 7eaad43..89c8403 100644
--- a/DocFormats/core/src/lib/DFHashTable.h
+++ b/DocFormats/core/src/lib/DFHashTable.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFHashTable_h
 #define DocFormats_DFHashTable_h
diff --git a/DocFormats/core/src/lib/DFStorage.c b/DocFormats/core/src/lib/DFStorage.c
index 04521aa..d6e404f 100644
--- a/DocFormats/core/src/lib/DFStorage.c
+++ b/DocFormats/core/src/lib/DFStorage.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include <DocFormats/DFStorage.h>
@@ -70,13 +73,13 @@
 
     size_t balloc = 4096;
     size_t blen = 0;
-    char *mem = (char *)malloc(balloc);
+    char *mem = (char *)xmalloc(balloc);
 
     size_t r;
     while (0 < (r = fread(&mem[blen],1,4096,file))) {
         balloc += r;
         blen += r;
-        mem = (char *)realloc(mem,balloc);
+        mem = (char *)xrealloc(mem,balloc);
     }
     ok = 1;
 
@@ -142,7 +145,7 @@
     if (allPaths == NULL)
         return NULL;;
 
-    DFArray *filesOnly = DFArrayNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    DFArray *filesOnly = DFArrayNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
     for (int i = 0; allPaths[i]; i++) {
         const char *relPath = allPaths[i];
         char *absPath = DFAppendPathComponent(storage->rootPath,relPath);
@@ -187,7 +190,7 @@
         return 0;
     }
 
-    *buf = malloc(buffer->len);
+    *buf = xmalloc(buffer->len);
     memcpy(*buf,buffer->data,buffer->len);
     *nbytes = buffer->len;
 
@@ -255,7 +258,7 @@
         return 0;
     }
 
-    *buf = malloc(buffer->len);
+    *buf = xmalloc(buffer->len);
     memcpy(*buf,buffer->data,buffer->len);
     *nbytes = buffer->len;
 
@@ -312,16 +315,16 @@
     char *normalized = DFPathNormalize(input);
     char *result;
     if (normalized[0] == '/')
-        result = strdup(&normalized[1]);
+        result = xstrdup(&normalized[1]);
     else
-        result = strdup(normalized);
+        result = xstrdup(normalized);
     free(normalized);
     return result;
 }
 
 static DFStorage *DFStorageNew(DFFileFormat format, const DFStorageOps *ops)
 {
-    DFStorage *storage = (DFStorage *)calloc(1,sizeof(DFStorage));
+    DFStorage *storage = (DFStorage *)xcalloc(1,sizeof(DFStorage));
     storage->retainCount = 1;
     storage->format = format;
     storage->ops = ops;
@@ -333,7 +336,7 @@
     if ((rootPath == NULL) || (strlen(rootPath) == 0))
         rootPath = ".";;
     DFStorage *storage = DFStorageNew(format,&fsOps);
-    storage->rootPath = strdup(rootPath);
+    storage->rootPath = xstrdup(rootPath);
     return storage;
 }
 
@@ -354,7 +357,7 @@
 
     DFStorage *storage = DFStorageNew(DFFileFormatFromFilename(filename),&zipOps);
     storage->files = DFHashTableNew((DFCopyFunction)DFBufferRetain,(DFFreeFunction)DFBufferRelease);
-    storage->zipFilename = strdup(filename);
+    storage->zipFilename = xstrdup(filename);
     return storage;
 }
 
@@ -367,7 +370,7 @@
 
     DFStorage *storage = DFStorageNew(DFFileFormatFromFilename(filename),&zipOps);
     storage->files = DFHashTableNew((DFCopyFunction)DFBufferRetain,(DFFreeFunction)DFBufferRelease);
-    storage->zipFilename = strdup(filename);
+    storage->zipFilename = xstrdup(filename);
 
     if (!DFUnzip(filename,storage,error)) {
         DFStorageRelease(storage);
diff --git a/DocFormats/core/src/lib/DFString.c b/DocFormats/core/src/lib/DFString.c
index b768ef4..243439a 100644
--- a/DocFormats/core/src/lib/DFString.c
+++ b/DocFormats/core/src/lib/DFString.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFString.h"
@@ -50,13 +53,13 @@
     }
 
     builder->pointerIndex += 1;
-    builder->storageIndex += toklen + 1;
+    builder->storageIndex += (int)(toklen + 1);
 }
 
 static void DFArrayBuilderAllocate(DFArrayBuilder *builder)
 {
     int pointerBytes = (builder->pointerIndex + 1)*sizeof(char *);
-    void *mem = malloc(pointerBytes + builder->storageIndex);
+    void *mem = xmalloc(pointerBytes + builder->storageIndex);
     builder->pointers = mem;
     builder->storage = (char *)mem + pointerBytes;
 }
@@ -253,7 +256,7 @@
         ch = DFNextChar(str,&pos);
     } while ((ch != 0) && DFCharIsWhitespaceOrNewline(ch));
 
-    return strdup(&str[startpos]);
+    return xstrdup(&str[startpos]);
 }
 
 char *DFStringNormalizeWhitespace(const char *input)
@@ -265,7 +268,7 @@
     size_t inputLen = strlen(input);
     size_t outputLen = 0;
 
-    char *output = (char *)malloc(inputLen+1);
+    char *output = (char *)xmalloc(inputLen+1);
 
     size_t start = 0;
     while ((start < inputLen) && isspace(input[start]))
@@ -310,7 +313,7 @@
     if (end < start)
         end = start;
 
-    char *substring = (char *)malloc(end-start+1);
+    char *substring = (char *)xmalloc(end-start+1);
     memcpy(substring,&str[start],end-start);
     substring[end-start] = '\0';
     return substring;
@@ -319,7 +322,7 @@
 char *DFStrDup(const char *str)
 {
     if (str != NULL)
-        return strdup(str);
+        return xstrdup(str);
     else
         return NULL;
 }
@@ -331,7 +334,7 @@
     }
 
     size_t len = strlen(input);
-    char *result = strdup(input);
+    char *result = xstrdup(input);
     for (size_t i = 0; i < len; i++) {
         // Avoid calling toupper with chars from UTF-8 multibyte sequences
         if ((result[i] >= 'a') && result[i] <= 'z')
@@ -347,7 +350,7 @@
     }
 
     size_t len = strlen(input);
-    char *result = strdup(input);
+    char *result = xstrdup(input);
     for (size_t i = 0; i < len; i++) {
         // Avoid calling tolower with chars from UTF-8 multibyte sequences
         if ((result[i] >= 'A') && result[i] <= 'Z')
@@ -364,7 +367,7 @@
     size_t nchars = vsnprintf(NULL,0,format,ap2);
     va_end(ap2);
 
-    char *result = (char *)malloc(nchars+1);
+    char *result = (char *)xmalloc(nchars+1);
 
     va_copy(ap2,ap);
     vsnprintf(result,nchars+1,format,ap2);
@@ -486,7 +489,7 @@
 {
     char *unnormalized;
     if (strlen(path1) == 0)
-        unnormalized = strdup(path2);
+        unnormalized = xstrdup(path2);
     else if (path1[strlen(path1)-1] == '/')
         unnormalized = DFFormatString("%s%s",path1,path2);
     else
@@ -509,7 +512,7 @@
     size_t matchLen = strlen(match);
 
     if (matchLen == 0)
-        return strdup(input); // protect against infinite loop
+        return xstrdup(input); // protect against infinite loop
 
     struct DFBuffer *output = DFBufferNew();
 
@@ -525,7 +528,7 @@
         }
     }
 
-    char *result = strdup(output->data);
+    char *result = xstrdup(output->data);
     DFBufferRelease(output);
     return result;
 }
@@ -544,7 +547,7 @@
     // UTF-8 characters pass through untouched.
 
     size_t inlen = strlen(in);
-    char *out = (char*)malloc(2*inlen+3);
+    char *out = (char*)xmalloc(2*inlen+3);
     size_t outlen = 0;
     out[outlen++] = '"';
     for (size_t i = 0; i < inlen; i++) {
@@ -595,11 +598,11 @@
         return NULL;
 
     if ((in[0] != '"') && (in[0] != '\''))
-        return strdup(in);
+        return xstrdup(in);
     char quote = in[0];
 
     size_t inlen = strlen(in);
-    char *out = (char *)malloc(inlen+1);
+    char *out = (char *)xmalloc(inlen+1);
     size_t outlen = 0;
     size_t i = 1;
     for (; i < inlen; i++) {
@@ -643,7 +646,7 @@
 char *DFSpacesToUnderscores(const char *input)
 {
     size_t len = strlen(input);
-    char *output = strdup(input);
+    char *output = xstrdup(input);
     for (size_t i = 0; i < len; i++) {
         if (output[i] == ' ')
             output[i] = '_';
@@ -654,7 +657,7 @@
 char *DFUnderscoresToSpaces(const char *input)
 {
     size_t len = strlen(input);
-    char *output = strdup(input);
+    char *output = xstrdup(input);
     for (size_t i = 0; i < len; i++) {
         if (output[i] == '_')
             output[i] = ' ';
@@ -736,7 +739,7 @@
     DFBuffer *buffer = DFBufferReadFromFile(filename,error);
     if (buffer == NULL)
         return NULL;
-    char *result = strdup(buffer->data);
+    char *result = xstrdup(buffer->data);
     DFBufferRelease(buffer);
     return result;
 }
@@ -770,7 +773,7 @@
     while (DFNextChar(input,&inpos) != 0)
         outlen++;
 
-    uint32_t *output = (uint32_t *)malloc((outlen+1)*sizeof(uint32_t));
+    uint32_t *output = (uint32_t *)xmalloc((outlen+1)*sizeof(uint32_t));
     inpos = 0;
     for (size_t outpos = 0; outpos < outlen; outpos++)
         output[outpos] = DFNextChar(input,&inpos);
@@ -848,7 +851,7 @@
     }
 
     size_t outlen = DFUTF32to8n(input,NULL);
-    char *output = (char *)malloc(outlen+1);
+    char *output = (char *)xmalloc(outlen+1);
     DFUTF32to8n(input,output);
     output[outlen] = '\0';
 
diff --git a/DocFormats/core/src/lib/DFString.h b/DocFormats/core/src/lib/DFString.h
index 5530c61..75856c2 100644
--- a/DocFormats/core/src/lib/DFString.h
+++ b/DocFormats/core/src/lib/DFString.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFString_h
 #define DocFormats_DFString_h
diff --git a/DocFormats/core/src/lib/DFZipFile.c b/DocFormats/core/src/lib/DFZipFile.c
index faec05f..ee5a648 100644
--- a/DocFormats/core/src/lib/DFZipFile.c
+++ b/DocFormats/core/src/lib/DFZipFile.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFZipFile.h"
diff --git a/DocFormats/core/src/lib/DFZipFile.h b/DocFormats/core/src/lib/DFZipFile.h
index 332cace..10fe461 100644
--- a/DocFormats/core/src/lib/DFZipFile.h
+++ b/DocFormats/core/src/lib/DFZipFile.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFZipFile_h
 #define DocFormats_DFZipFile_h
diff --git a/DocFormats/core/src/lib/TextPackage.c b/DocFormats/core/src/lib/TextPackage.c
index b81a42e..feff1d6 100644
--- a/DocFormats/core/src/lib/TextPackage.c
+++ b/DocFormats/core/src/lib/TextPackage.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "TextPackage.h"
@@ -29,10 +32,10 @@
 
 static TextPackage *TextPackageNew(void)
 {
-    TextPackage *package = (TextPackage *)calloc(1,sizeof(TextPackage));
+    TextPackage *package = (TextPackage *)xcalloc(1,sizeof(TextPackage));
     package->retainCount = 1;
-    package->items = DFHashTableNew((DFCopyFunction)strdup,free);
-    package->keys = (char **)calloc(1,sizeof(char *));
+    package->items = DFHashTableNew((DFCopyFunction)xstrdup,free);
+    package->keys = (char **)xcalloc(1,sizeof(char *));
     return package;
 }
 
@@ -98,7 +101,7 @@
     }
 
 
-    char *currentKey = strdup("");
+    char *currentKey = xstrdup("");
     DFBuffer *currentValue = DFBufferNew();
     const char **lines = DFStringSplit(replaced->data,"\n",0);
     for (int lineno = 0; lines[lineno]; lineno++) {
@@ -108,8 +111,8 @@
             DFBufferFormat(currentValue,"%s\n",line);
         }
         else if (DFStringHasPrefix(line,"#item ")) {
-            package->keys = (char **)realloc(package->keys,(package->nkeys+2)*sizeof(char *));
-            package->keys[package->nkeys++] = strdup(currentKey);
+            package->keys = (char **)xrealloc(package->keys,(package->nkeys+2)*sizeof(char *));
+            package->keys[package->nkeys++] = xstrdup(currentKey);
             package->keys[package->nkeys] = NULL;
             DFHashTableAdd(package->items,currentKey,currentValue->data);
             free(currentKey);
@@ -125,8 +128,8 @@
             return 0;
         }
     }
-    package->keys = (char **)realloc(package->keys,(package->nkeys+2)*sizeof(char *));
-    package->keys[package->nkeys++] = strdup(currentKey);
+    package->keys = (char **)xrealloc(package->keys,(package->nkeys+2)*sizeof(char *));
+    package->keys[package->nkeys++] = xstrdup(currentKey);
     package->keys[package->nkeys] = NULL;
     DFHashTableAdd(package->items,currentKey,currentValue->data);
 
diff --git a/DocFormats/core/src/lib/TextPackage.h b/DocFormats/core/src/lib/TextPackage.h
index 077f84e..2edb3d6 100644
--- a/DocFormats/core/src/lib/TextPackage.h
+++ b/DocFormats/core/src/lib/TextPackage.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef dfutil_TextPackage_h
 #define dfutil_TextPackage_h
diff --git a/DocFormats/core/src/xml/DFChanges.c b/DocFormats/core/src/xml/DFChanges.c
index 8dd44de..c67b0f0 100644
--- a/DocFormats/core/src/xml/DFChanges.c
+++ b/DocFormats/core/src/xml/DFChanges.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFChanges.h"
@@ -27,7 +30,7 @@
     const TagDecl *tagDecl = DFNameMapNameForTag(doc->map,tag);
     const NamespaceDecl *nsDecl = DFNameMapNamespaceForID(doc->map,tagDecl->namespaceID);
     if ((nsDecl->prefix == NULL) || (tagDecl->namespaceID == NAMESPACE_HTML))
-        return strdup(tagDecl->localName);
+        return xstrdup(tagDecl->localName);
     else
         return DFFormatString("%s:%s",nsDecl->prefix,tagDecl->localName);
 }
@@ -78,7 +81,7 @@
                     if (strlen(quoted) >= 2)
                         sub = DFSubstring(quoted,1,strlen(quoted)-2);
                     else
-                        sub = strdup(quoted);
+                        sub = xstrdup(quoted);
                     DFBufferFormat(output,"%s</%s>",quoted,elementName);
                     free(sub);
                     free(quoted);
@@ -216,7 +219,7 @@
 {
     DFBuffer *output = DFBufferNew();
     DFChangesToStringRecursive(root,0,output);
-    char *result = strdup(output->data);
+    char *result = xstrdup(output->data);
     DFBufferRelease(output);
     return result;
 }
diff --git a/DocFormats/core/src/xml/DFChanges.h b/DocFormats/core/src/xml/DFChanges.h
index 16759e4..939c352 100644
--- a/DocFormats/core/src/xml/DFChanges.h
+++ b/DocFormats/core/src/xml/DFChanges.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef dfutil_DFChanges_h
 #define dfutil_DFChanges_h
diff --git a/DocFormats/core/src/xml/DFDOM.c b/DocFormats/core/src/xml/DFDOM.c
index 413880e..a5ef758 100644
--- a/DocFormats/core/src/xml/DFDOM.c
+++ b/DocFormats/core/src/xml/DFDOM.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFDOM.h"
@@ -46,7 +49,7 @@
 {
     if (doc->nodesCount == doc->nodesAlloc) {
         doc->nodesAlloc *= 2;
-        doc->nodes = (DFNode **)realloc(doc->nodes,doc->nodesAlloc*sizeof(DFNode *));
+        doc->nodes = (DFNode **)xrealloc(doc->nodes,doc->nodesAlloc*sizeof(DFNode *));
     }
 
 //    Node *node = NodeNew(tag);
@@ -60,7 +63,7 @@
 
 DFDocument *DFDocumentNew(void)
 {
-    DFDocument *doc = (DFDocument *)calloc(1,sizeof(DFDocument));
+    DFDocument *doc = (DFDocument *)xcalloc(1,sizeof(DFDocument));
     doc->retainCount = 1;
     doc->allocator = DFAllocatorNew();
     doc->map = DFNameMapNew();
@@ -68,7 +71,7 @@
 
     doc->nodesCount = 0;
     doc->nodesAlloc = 1;
-    doc->nodes = (DFNode **)malloc(doc->nodesAlloc*sizeof(DFNode *));
+    doc->nodes = (DFNode **)xmalloc(doc->nodesAlloc*sizeof(DFNode *));
     doc->docNode = DocumentCreateNode(doc,DOM_DOCUMENT);
 
     return doc;
@@ -339,7 +342,7 @@
     // No existing attribute with this tag - add it
     if (element->attrsCount == element->attrsAlloc) {
         element->attrsAlloc = (element->attrsAlloc == 0) ? 8 : (2*element->attrsAlloc);
-        element->attrs = (DFAttribute *)realloc(element->attrs,element->attrsAlloc*sizeof(DFAttribute));
+        element->attrs = (DFAttribute *)xrealloc(element->attrs,element->attrsAlloc*sizeof(DFAttribute));
     }
 
     element->attrs[element->attrsCount].tag = tag;
@@ -485,7 +488,7 @@
 {
     DFBuffer *buf = DFBufferNew();
     DFNodeTextToBuffer(node,buf);
-    char *result = strdup(buf->data);
+    char *result = xstrdup(buf->data);
     DFBufferRelease(buf);
     return result;
 }
diff --git a/DocFormats/core/src/xml/DFDOM.h b/DocFormats/core/src/xml/DFDOM.h
index 1ea863e..44e81fe 100644
--- a/DocFormats/core/src/xml/DFDOM.h
+++ b/DocFormats/core/src/xml/DFDOM.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFDOM_h
 #define DocFormats_DFDOM_h
diff --git a/DocFormats/core/src/xml/DFMarkupCompatibility.c b/DocFormats/core/src/xml/DFMarkupCompatibility.c
index 33dc69d..a77a08d 100644
--- a/DocFormats/core/src/xml/DFMarkupCompatibility.c
+++ b/DocFormats/core/src/xml/DFMarkupCompatibility.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFMarkupCompatibility.h"
@@ -56,7 +59,7 @@
 
 DFMarkupCompatibility *DFMarkupCompatibilityNew(void)
 {
-    DFMarkupCompatibility *mc = (DFMarkupCompatibility *)calloc(1,sizeof(DFMarkupCompatibility));
+    DFMarkupCompatibility *mc = (DFMarkupCompatibility *)xcalloc(1,sizeof(DFMarkupCompatibility));
     return mc;
 }
 
@@ -70,7 +73,7 @@
 static void addDeclToRecord(MCRecord *record, NamespaceID nsId, Tag tag, MCAction action)
 {
     record->count++;
-    record->decls = (MCDecl *)realloc(record->decls,record->count*sizeof(MCDecl));
+    record->decls = (MCDecl *)xrealloc(record->decls,record->count*sizeof(MCDecl));
     record->decls[record->count-1].nsId = nsId;
     record->decls[record->count-1].tag = tag;
     record->decls[record->count-1].action = action;
@@ -83,7 +86,7 @@
         MCRecord *record = &mc->records[mc->depth-1];
         bzero(record,sizeof(MCRecord));
         if (nb_namespaces > 0) {
-            record->namespaces = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+            record->namespaces = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
             for (int i = 0; i < nb_namespaces; i++) {
                 const char *nsPrefix = namespaces[i*2];
                 const char *nsURI = namespaces[i*2+1];
@@ -152,7 +155,7 @@
             localName = DFSubstring(component,colonPos+1,strlen(component));
         }
         else {
-            prefix = strdup(component);
+            prefix = xstrdup(component);
             localName = NULL;
         }
 
diff --git a/DocFormats/core/src/xml/DFMarkupCompatibility.h b/DocFormats/core/src/xml/DFMarkupCompatibility.h
index d421d54..c8a5273 100644
--- a/DocFormats/core/src/xml/DFMarkupCompatibility.h
+++ b/DocFormats/core/src/xml/DFMarkupCompatibility.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFMarkupCompatibility_h
 #define DocFormats_DFMarkupCompatibility_h
diff --git a/DocFormats/core/src/xml/DFNameMap.c b/DocFormats/core/src/xml/DFNameMap.c
index f408003..eb5d868 100644
--- a/DocFormats/core/src/xml/DFNameMap.c
+++ b/DocFormats/core/src/xml/DFNameMap.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFNameMap.h"
@@ -76,9 +79,9 @@
     if (URI == NULL)
         URI = "";;
     uint32_t hash = DFNameHashTableHash(name,URI)%HASH_TABLE_SIZE;
-    DFNameEntry *entry = (DFNameEntry *)malloc(sizeof(DFNameEntry));
-    entry->name = strdup(name);
-    entry->URI = strdup(URI);
+    DFNameEntry *entry = (DFNameEntry *)xmalloc(sizeof(DFNameEntry));
+    entry->name = xstrdup(name);
+    entry->URI = xstrdup(URI);
     entry->tag = tag;
     entry->tagDecl.namespaceID = namespaceID;
     entry->tagDecl.localName = (const char *)entry->name;
@@ -88,7 +91,7 @@
 
 static DFNameHashTable *DFNameHashTableNew()
 {
-    return (DFNameHashTable*)calloc(1,sizeof(DFNameHashTable));
+    return (DFNameHashTable*)xcalloc(1,sizeof(DFNameHashTable));
 }
 
 static void DFNameHashTableFree(DFNameHashTable *table)
@@ -121,11 +124,11 @@
 
 DFNamespaceInfo *DFNamespaceInfoNew(NamespaceID nsId, const char *URI, const char *prefix)
 {
-    DFNamespaceInfo *info = (DFNamespaceInfo *)calloc(1,sizeof(DFNamespaceInfo));
+    DFNamespaceInfo *info = (DFNamespaceInfo *)xcalloc(1,sizeof(DFNamespaceInfo));
     info->nsId = nsId;
-    info->decl = (NamespaceDecl *)malloc(sizeof(NamespaceDecl));
-    info->decl->namespaceURI = strdup(URI);
-    info->decl->prefix = strdup(prefix);
+    info->decl = (NamespaceDecl *)xmalloc(sizeof(NamespaceDecl));
+    info->decl->namespaceURI = xstrdup(URI);
+    info->decl->prefix = xstrdup(prefix);
     return info;
 }
 
@@ -152,11 +155,11 @@
 
 DFTagInfo *DFTagInfoNew(Tag tag, NamespaceID nsId, const char *localName)
 {
-    DFTagInfo *info = (DFTagInfo *)calloc(1,sizeof(DFTagInfo));
+    DFTagInfo *info = (DFTagInfo *)xcalloc(1,sizeof(DFTagInfo));
     info->tag = tag;
-    info->decl = (TagDecl *)malloc(sizeof(TagDecl));
+    info->decl = (TagDecl *)xmalloc(sizeof(TagDecl));
     info->decl->namespaceID = nsId;
-    info->decl->localName = strdup(localName);
+    info->decl->localName = xstrdup(localName);
     return info;
 }
 
@@ -192,7 +195,7 @@
 
 DFNameMap *DFNameMapNew(void)
 {
-    DFNameMap *map = (DFNameMap *)calloc(1,sizeof(DFNameMap));
+    DFNameMap *map = (DFNameMap *)xcalloc(1,sizeof(DFNameMap));
     map->namespacesByID = DFHashTableNew2(NULL,NULL,997);
     map->namespacesByURI = DFHashTableNew2(NULL,(DFFreeFunction)DFNamespaceInfoFree,997);
     map->tagsByID = DFHashTableNew2(NULL,(DFFreeFunction)DFTagInfoFree,997);
diff --git a/DocFormats/core/src/xml/DFNameMap.h b/DocFormats/core/src/xml/DFNameMap.h
index 9be2c39..1a8c76b 100644
--- a/DocFormats/core/src/xml/DFNameMap.h
+++ b/DocFormats/core/src/xml/DFNameMap.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFNameMap_h
 #define DocFormats_DFNameMap_h
diff --git a/DocFormats/core/src/xml/DFXML.c b/DocFormats/core/src/xml/DFXML.c
index 2172651..449f2e1 100644
--- a/DocFormats/core/src/xml/DFXML.c
+++ b/DocFormats/core/src/xml/DFXML.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFXML.h"
@@ -70,7 +73,7 @@
 
 DFSAXParser *DFSAXParserNew(void)
 {
-    DFSAXParser *parser = (DFSAXParser *)calloc(1,sizeof(DFSAXParser));
+    DFSAXParser *parser = (DFSAXParser *)xcalloc(1,sizeof(DFSAXParser));
     parser->document = DFDocumentNew();
     parser->parent = parser->document->docNode;
     parser->warnings = DFBufferNew();
@@ -136,11 +139,11 @@
         const xmlChar *attrURI = attributes[i*5+2];
         const xmlChar *attrValueStart = attributes[i*5+3];
         const xmlChar *attrValueEnd = attributes[i*5+4];
-        unsigned long attrValueLen = attrValueEnd - attrValueStart;
+        unsigned long attrValueLen = (unsigned long)(attrValueEnd - attrValueStart);
 
         Tag attrTag = DFNameMapTagForName(parser->document->map,(const char *)attrURI,(const char *)attrLocalName);
         const TagDecl *attrTagDecl = DFNameMapNameForTag(parser->document->map,attrTag);
-        char *attrValue = (char *)malloc(attrValueLen+1);
+        char *attrValue = (char *)xmalloc(attrValueLen+1);
         memcpy(attrValue,attrValueStart,attrValueLen);
         attrValue[attrValueLen] = '\0';
         if (parser->compatibility != NULL) {
@@ -223,7 +226,7 @@
     DFSAXParser *parser = (DFSAXParser *)ctx;
     if (parser->ignoreDepth > 0)
         return;
-    char *data = (char *)malloc(len+1);
+    char *data = (char *)xmalloc(len+1);
     memcpy(data,ch,len);
     data[len] = '\0';
     DFNode *text = DFCreateTextNode(parser->document,data);
@@ -247,7 +250,7 @@
     DFSAXParser *parser = (DFSAXParser *)ctx;
     if (parser->ignoreDepth > 0)
         return;
-    char *data = (char *)malloc(len+1);
+    char *data = (char *)xmalloc(len+1);
     memcpy(data,value,len);
     data[len] = '\0';
     DFNode *cdata = DFCreateTextNode(parser->document,data);
@@ -357,7 +360,7 @@
 static void writeNamespaceDeclarations(Serialization *serialization, DFNode *node)
 {
     NamespaceID count = DFNameMapNamespaceCount(serialization->doc->map);
-    char *used = (char *)calloc(1,count);
+    char *used = (char *)xcalloc(1,count);
     findUsedNamespaces(serialization->doc,node,used,count);
     for (NamespaceID nsId = 1; nsId < count; nsId++) { // don't write null namespace
         if (used[nsId]) {
@@ -389,7 +392,7 @@
 {
     // Sort the keys by their tag, to ensure that we always write attributes out in the same order.
     // This is important for automated tests which rely on consistent output for a given XML tree.
-    DFAttribute *attrs = (DFAttribute *)malloc(element->attrsCount*sizeof(DFAttribute));
+    DFAttribute *attrs = (DFAttribute *)xmalloc(element->attrsCount*sizeof(DFAttribute));
     memcpy(attrs,element->attrs,element->attrsCount*sizeof(DFAttribute));
     qsort(attrs,element->attrsCount,sizeof(DFAttribute),compareAttrs);
 
@@ -608,7 +611,7 @@
 {
     DFBuffer *buf = DFBufferNew();
     DFSerializeXMLBuffer(doc,defaultNS,indent,buf);
-    char *result = strdup(buf->data);
+    char *result = xstrdup(buf->data);
     DFBufferRelease(buf);
     return result;
 }
diff --git a/DocFormats/core/src/xml/DFXML.h b/DocFormats/core/src/xml/DFXML.h
index 3318706..a36c638 100644
--- a/DocFormats/core/src/xml/DFXML.h
+++ b/DocFormats/core/src/xml/DFXML.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFXML_h
 #define DocFormats_DFXML_h
diff --git a/DocFormats/core/tests/common/BDTTests.c b/DocFormats/core/tests/common/BDTTests.c
index df10d02..5fdb8c4 100644
--- a/DocFormats/core/tests/common/BDTTests.c
+++ b/DocFormats/core/tests/common/BDTTests.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "BDTTests.h"
@@ -40,7 +43,7 @@
 
 static ItemLens *ItemLensNew(DFDocument *abstractDoc, DFDocument *concreteDoc)
 {
-    ItemLens *lens = (ItemLens *)calloc(1,sizeof(ItemLens));
+    ItemLens *lens = (ItemLens *)xcalloc(1,sizeof(ItemLens));
     lens->abstractDoc = DFDocumentRetain(abstractDoc);
     lens->concreteDoc = DFDocumentRetain(concreteDoc);
     return lens;
@@ -126,7 +129,7 @@
 
 static TestContainerLens *TestContainerLensNew(DFDocument *abstractDoc, DFDocument *concreteDoc)
 {
-    TestContainerLens *lens = (TestContainerLens *)calloc(1,sizeof(TestContainerLens));
+    TestContainerLens *lens = (TestContainerLens *)xcalloc(1,sizeof(TestContainerLens));
     lens->abstractDoc = DFDocumentRetain(abstractDoc);
     lens->concreteDoc = DFDocumentRetain(concreteDoc);
     lens->itemLens = ItemLensNew(abstractDoc,concreteDoc);
@@ -389,7 +392,7 @@
 
 static void test_remove(void)
 {
-    int *indices = (int *)malloc(utgetargc()*sizeof(int));
+    int *indices = (int *)xmalloc(utgetargc()*sizeof(int));
 
     for (int i = 0; i < utgetargc(); i++) {
         int index = atoi(utgetargv()[i]);
diff --git a/DocFormats/core/tests/common/BDTTests.h b/DocFormats/core/tests/common/BDTTests.h
index f4bae09..7e1b63a 100644
--- a/DocFormats/core/tests/common/BDTTests.h
+++ b/DocFormats/core/tests/common/BDTTests.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef dfutil_BDTTest_h
 #define dfutil_BDTTest_h
diff --git a/DocFormats/core/tests/css/CSSTests.c b/DocFormats/core/tests/css/CSSTests.c
index 4612588..ae18dce 100644
--- a/DocFormats/core/tests/css/CSSTests.c
+++ b/DocFormats/core/tests/css/CSSTests.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFUnitTest.h"
diff --git a/DocFormats/core/tests/html/HTMLPlain.c b/DocFormats/core/tests/html/HTMLPlain.c
index d260de4..e131f43 100644
--- a/DocFormats/core/tests/html/HTMLPlain.c
+++ b/DocFormats/core/tests/html/HTMLPlain.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "HTMLPlain.h"
@@ -74,7 +77,7 @@
     }
     free(imageSources);
 
-    char *str = strdup(output->data);
+    char *str = xstrdup(output->data);
     DFBufferRelease(output);
     return str;
 }
diff --git a/DocFormats/core/tests/html/HTMLPlain.h b/DocFormats/core/tests/html/HTMLPlain.h
index 210282e..8d32917 100644
--- a/DocFormats/core/tests/html/HTMLPlain.h
+++ b/DocFormats/core/tests/html/HTMLPlain.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_HTMLPlain_h
 #define DocFormats_HTMLPlain_h
diff --git a/DocFormats/core/tests/html/HTMLTests.c b/DocFormats/core/tests/html/HTMLTests.c
index 76a1424..620182d 100644
--- a/DocFormats/core/tests/html/HTMLTests.c
+++ b/DocFormats/core/tests/html/HTMLTests.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFUnitTest.h"
diff --git a/DocFormats/core/tests/lib/LibTests.c b/DocFormats/core/tests/lib/LibTests.c
index cbf3bc7..b4382c9 100644
--- a/DocFormats/core/tests/lib/LibTests.c
+++ b/DocFormats/core/tests/lib/LibTests.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFUnitTest.h"
 #include <stddef.h>
diff --git a/DocFormats/core/tests/xml/XMLTests.c b/DocFormats/core/tests/xml/XMLTests.c
index a7ca32b..da4480d 100644
--- a/DocFormats/core/tests/xml/XMLTests.c
+++ b/DocFormats/core/tests/xml/XMLTests.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFUnitTest.h"
 #include <stddef.h>
diff --git a/DocFormats/filters/latex/src/HTMLToLaTeX.c b/DocFormats/filters/latex/src/HTMLToLaTeX.c
index 10be122..20589f8 100644
--- a/DocFormats/filters/latex/src/HTMLToLaTeX.c
+++ b/DocFormats/filters/latex/src/HTMLToLaTeX.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "HTMLToLaTeX.h"
@@ -40,9 +43,9 @@
 
 LaTeXConverter *LaTeXConverterNew(DFDocument *htmlDoc)
 {
-    LaTeXConverter *conv = (LaTeXConverter *)calloc(1,sizeof(LaTeXConverter));
+    LaTeXConverter *conv = (LaTeXConverter *)xcalloc(1,sizeof(LaTeXConverter));
     conv->htmlDoc = DFDocumentRetain(htmlDoc);
-    conv->packages = DFHashTableNew((DFCopyFunction)strdup,free);
+    conv->packages = DFHashTableNew((DFCopyFunction)xstrdup,free);
     return conv;
 }
 
@@ -232,7 +235,7 @@
             }
 
             if (texWidth == NULL)
-                texWidth = strdup("");;
+                texWidth = xstrdup("");;
 
             const char *src = DFGetAttribute(node,HTML_SRC);
             if (src != NULL) {
@@ -681,7 +684,7 @@
 
     DFBufferFormat(mainOutput,"\\end{document}\n");
 
-    char *result = strdup(mainOutput->data);
+    char *result = xstrdup(mainOutput->data);
     DFBufferRelease(makeTitleOutput);
     DFBufferRelease(documentOutput);
     DFBufferRelease(mainOutput);
diff --git a/DocFormats/filters/latex/src/HTMLToLaTeX.h b/DocFormats/filters/latex/src/HTMLToLaTeX.h
index 6c71282..e0faa2e 100644
--- a/DocFormats/filters/latex/src/HTMLToLaTeX.h
+++ b/DocFormats/filters/latex/src/HTMLToLaTeX.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_HTMLToLaTeX_h
 #define DocFormats_HTMLToLaTeX_h
diff --git a/DocFormats/filters/latex/tests/LaTeXTests.c b/DocFormats/filters/latex/tests/LaTeXTests.c
index 16a113c..65cb9f7 100644
--- a/DocFormats/filters/latex/tests/LaTeXTests.c
+++ b/DocFormats/filters/latex/tests/LaTeXTests.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFUnitTest.h"
diff --git a/DocFormats/filters/odf/CMakeLists.txt b/DocFormats/filters/odf/CMakeLists.txt
index 7787ad6..b38a965 100644
--- a/DocFormats/filters/odf/CMakeLists.txt
+++ b/DocFormats/filters/odf/CMakeLists.txt
@@ -25,6 +25,10 @@
     src/ODFSheet.c
     src/ODFSheet.h)
 
+set(GroupSrcText
+    src/text/ODFText.h
+    src/text/ODFText.c)
+
 set(GroupTests
     tests/ODFTests.c)
 
@@ -62,7 +66,9 @@
 ###
 add_library(odf OBJECT
     ${GroupSrc}
+    ${GroupSrcText}
     ${GroupTests})
-source_group(src   FILES ${GroupSrc})
-source_group(tests FILES ${GroupTests})
+source_group(src         FILES ${GroupSrc})
+source_group(src\\text   FILES ${GroupSrcText})
+source_group(tests       FILES ${GroupTests})
 set_property(TARGET odf PROPERTY FOLDER DocFormats/filters)
diff --git a/DocFormats/filters/odf/src/ODF.c b/DocFormats/filters/odf/src/ODF.c
index 299fc95..f2091de 100644
--- a/DocFormats/filters/odf/src/ODF.c
+++ b/DocFormats/filters/odf/src/ODF.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "ODF.h"
diff --git a/DocFormats/filters/odf/src/ODF.h b/DocFormats/filters/odf/src/ODF.h
index 245429f..b9afb52 100644
--- a/DocFormats/filters/odf/src/ODF.h
+++ b/DocFormats/filters/odf/src/ODF.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_ODF_h
 #define DocFormats_ODF_h
diff --git a/DocFormats/filters/odf/src/ODFManifest.c b/DocFormats/filters/odf/src/ODFManifest.c
index 843408b..b24c4eb 100644
--- a/DocFormats/filters/odf/src/ODFManifest.c
+++ b/DocFormats/filters/odf/src/ODFManifest.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "ODFManifest.h"
@@ -32,7 +35,7 @@
 
 ODFManifest *ODFManifestNew(void)
 {
-    ODFManifest *manifest = (ODFManifest *)calloc(1,sizeof(ODFManifest));
+    ODFManifest *manifest = (ODFManifest *)xcalloc(1,sizeof(ODFManifest));
     manifest->retainCount = 1;
     manifest->doc = DFDocumentNewWithRoot(MF_MANIFEST);
     manifest->entriesByPath = DFHashTableNew(NULL,NULL);
@@ -41,7 +44,7 @@
 
 ODFManifest *ODFManifestNewWithDoc(DFDocument *doc)
 {
-    ODFManifest *manifest = (ODFManifest *)calloc(1,sizeof(ODFManifest));
+    ODFManifest *manifest = (ODFManifest *)xcalloc(1,sizeof(ODFManifest));
     manifest->doc = DFDocumentRetain(doc);
     manifest->entriesByPath = DFHashTableNew(NULL,NULL);
     ODFManifestParse(manifest);
diff --git a/DocFormats/filters/odf/src/ODFManifest.h b/DocFormats/filters/odf/src/ODFManifest.h
index 8902f53..45eb903 100644
--- a/DocFormats/filters/odf/src/ODFManifest.h
+++ b/DocFormats/filters/odf/src/ODFManifest.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_ODFManifest_h
 #define DocFormats_ODFManifest_h
diff --git a/DocFormats/filters/odf/src/ODFPackage.c b/DocFormats/filters/odf/src/ODFPackage.c
index c05c04c..3507586 100644
--- a/DocFormats/filters/odf/src/ODFPackage.c
+++ b/DocFormats/filters/odf/src/ODFPackage.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "ODFPackage.h"
@@ -22,33 +25,37 @@
 #include <stdlib.h>
 #include <string.h>
 
-static DFDocument *readOrCreateDocument(ODFPackage *package, const char *filename, Tag rootTag, Tag childTag)
+static DFDocument *createDocument(Tag rootTag, Tag childTag)
 {
-    char *fullPath = DFFormatString("%s/%s",package->tempPath,filename);
-    DFDocument *doc = DFParseXMLFile(fullPath,NULL);
-    free(fullPath);
-    if (doc != NULL)
-        return doc;
-
-    doc = DFDocumentNewWithRoot(rootTag);
+    DFDocument *doc = DFDocumentNewWithRoot(rootTag);
     DFCreateChildElement(doc->root,childTag);
     return doc;
 }
 
-static ODFManifest *readOrCreateManifest(ODFPackage *package)
+static DFDocument *readDocument(ODFPackage *package, const char *filename, DFError **error)
 {
-    char *fullPath = DFFormatString("%s/%s",package->tempPath,"META-INF/manifest.xml");
-    DFDocument *manifestDoc = DFParseXMLFile(fullPath,NULL);
-    free(fullPath);
-    return (manifestDoc != NULL) ? ODFManifestNewWithDoc(manifestDoc) : ODFManifestNew();
+    DFDocument *doc = DFParseXMLStorage(package->storage,filename,error);
+    if (doc == NULL) {
+        DFErrorFormat(error,"%s: %s",filename,DFErrorMessage(error));
+        return NULL;
+    }
+    return doc;
 }
 
-static int writeDocument(ODFPackage *package, DFDocument *doc, NamespaceID defaultNS, const char *filename, DFError **error)
+static ODFManifest *readManifest(ODFPackage *package, DFError **error)
 {
-    char *fullPath = DFFormatString("%s/%s",package->tempPath,filename);
-    int ok = DFSerializeXMLFile(doc,defaultNS,0,fullPath,error);
-    free(fullPath);
+    DFDocument *manifestDoc = DFParseXMLStorage(package->storage,"META-INF/manifest.xml",error);
+    if (manifestDoc == NULL) {
+        DFErrorFormat(error,"META-INF/manifest.xml: %s",DFErrorMessage(error));
+        return NULL;
+    }
+    return ODFManifestNewWithDoc(manifestDoc);
+}
 
+static int writeDocument(ODFPackage *package, DFDocument *doc, NamespaceID defaultNS,
+                         const char *filename, DFError **error)
+{
+    int ok = DFSerializeXMLStorage(doc,defaultNS,0,package->storage,filename,error);
     if (!ok)
         DFErrorFormat(error,"%s: %s",filename,DFErrorMessage(error));
     return ok;
@@ -56,38 +63,72 @@
 
 static int writeString(ODFPackage *package, const char *str, const char *filename, DFError **error)
 {
-    char *fullPath = DFFormatString("%s/%s",package->tempPath,filename);
-    int ok = DFStringWriteToFile(str,fullPath,error);
-    free(fullPath);
+    DFBuffer *buf = DFBufferNew();
+    DFBufferAppendString(buf,str);
+    int ok = DFBufferWriteToStorage(buf,package->storage,filename,error);
+    DFBufferRelease(buf);
 
     if (!ok)
         DFErrorFormat(error,"%s: %s",filename,DFErrorMessage(error));
     return ok;
 }
 
-ODFPackage *ODFPackageNew(const char *tempPath, DFError **error)
+ODFPackage *ODFPackageOpenNew(DFStorage *storage, DFError **error)
 {
-    ODFPackage *package = (ODFPackage *)calloc(1,sizeof(ODFPackage));
+    ODFPackage *package = (ODFPackage *)xcalloc(1,sizeof(ODFPackage));
     package->retainCount = 1;
-    package->tempPath = strdup(tempPath);
+    package->storage = DFStorageRetain(storage);
 
-    package->contentDoc = readOrCreateDocument(package,"content.xml",OFFICE_DOCUMENT_CONTENT,OFFICE_BODY);
-    package->metaDoc = readOrCreateDocument(package,"meta.xml",OFFICE_DOCUMENT_META,OFFICE_META);
-    package->settingsDoc = readOrCreateDocument(package,"settings.xml",OFFICE_DOCUMENT_SETTINGS,OFFICE_SETTINGS);
-    package->stylesDoc = readOrCreateDocument(package,"styles.xml",OFFICE_DOCUMENT_STYLES,OFFICE_STYLES);
+    // Create XML documents
+    package->contentDoc = createDocument(OFFICE_DOCUMENT_CONTENT,OFFICE_BODY);
+    package->metaDoc = createDocument(OFFICE_DOCUMENT_META,OFFICE_META);
+    package->settingsDoc = createDocument(OFFICE_DOCUMENT_SETTINGS,OFFICE_SETTINGS);
+    package->stylesDoc = createDocument(OFFICE_DOCUMENT_STYLES,OFFICE_STYLES);
 
-    package->manifest = readOrCreateManifest(package);
+    // Create manifst
+    package->manifest = ODFManifestNew();
     ODFManifestAddEntry(package->manifest,"/","application/vnd.oasis.opendocument.text","1.2");
     ODFManifestAddEntry(package->manifest,"content.xml","text/xml",NULL);
     ODFManifestAddEntry(package->manifest,"meta.xml","text/xml",NULL);
     ODFManifestAddEntry(package->manifest,"settings.xml","text/xml",NULL);
     ODFManifestAddEntry(package->manifest,"styles.xml","text/xml",NULL);
 
+    // Setup ODF objects
     package->sheet = ODFSheetNew(package->stylesDoc,package->contentDoc);
 
     return package;
 }
 
+ODFPackage *ODFPackageOpenFrom(DFStorage *storage, DFError **error)
+{
+    ODFPackage *package = (ODFPackage *)xcalloc(1,sizeof(ODFPackage));
+    package->retainCount = 1;
+    package->storage = DFStorageRetain(storage);
+
+    // Read XML documents
+    if ((package->contentDoc = readDocument(package,"content.xml",error)) == NULL)
+        goto end;
+    if ((package->metaDoc = readDocument(package,"meta.xml",error)) == NULL)
+        goto end;
+    if ((package->settingsDoc = readDocument(package,"settings.xml",error)) == NULL)
+        goto end;
+    if ((package->stylesDoc = readDocument(package,"styles.xml",error)) == NULL)
+        goto end;
+
+    // Read manifest
+    if ((package->manifest = readManifest(package,error)) == NULL)
+        goto end;
+
+    // Setup ODF objects
+    package->sheet = ODFSheetNew(package->stylesDoc,package->contentDoc);
+
+    return package;
+
+end:
+    ODFPackageRelease(package);
+    return NULL;
+}
+
 ODFPackage *ODFPackageRetain(ODFPackage *package)
 {
     if (package != NULL)
@@ -100,7 +141,7 @@
     if ((package == NULL) || (--package->retainCount > 0))
         return;
 
-    free(package->tempPath);
+    DFStorageRelease(package->storage);
     ODFManifestRelease(package->manifest);
     ODFSheetRelease(package->sheet);
     DFDocumentRelease(package->contentDoc);
@@ -112,13 +153,6 @@
 
 int ODFPackageSave(ODFPackage *package, DFError **error)
 {
-    char *metaInfPath = DFFormatString("%s/META-INF",package->tempPath);
-    if (!DFFileExists(metaInfPath) && !DFCreateDirectory(metaInfPath,1,error)) {
-        free(metaInfPath);
-        return 0;
-    }
-    free(metaInfPath);
-
     if (!writeDocument(package,package->contentDoc,NAMESPACE_NULL,"content.xml",error))
         return 0;
     if (!writeDocument(package,package->metaDoc,NAMESPACE_NULL,"meta.xml",error))
@@ -131,6 +165,8 @@
         return 0;
     if (!writeString(package,"application/vnd.oasis.opendocument.text","mimetype",error))
         return 0;
+    if (!DFStorageSave(package->storage,error))
+        return 0;
 
     return 1;
 }
diff --git a/DocFormats/filters/odf/src/ODFPackage.h b/DocFormats/filters/odf/src/ODFPackage.h
index 834fef6..e56ebc2 100644
--- a/DocFormats/filters/odf/src/ODFPackage.h
+++ b/DocFormats/filters/odf/src/ODFPackage.h
@@ -1,22 +1,26 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_ODFPackage_h
 #define DocFormats_ODFPackage_h
 
 #include <DocFormats/DFXMLForward.h>
 #include <DocFormats/DFError.h>
+#include <DocFormats/DFStorage.h>
 #include "ODFManifest.h"
 #include "ODFSheet.h"
 
@@ -24,7 +28,7 @@
 
 struct ODFPackage {
     size_t retainCount;
-    char *tempPath;
+    DFStorage *storage;
     DFDocument *contentDoc;
     DFDocument *metaDoc;
     DFDocument *settingsDoc;
@@ -33,7 +37,8 @@
     ODFSheet *sheet;
 };
 
-ODFPackage *ODFPackageNew(const char *tempPath, DFError **error);
+ODFPackage *ODFPackageOpenNew(DFStorage *storage, DFError **error);
+ODFPackage *ODFPackageOpenFrom(DFStorage *storage, DFError **error);
 ODFPackage *ODFPackageRetain(ODFPackage *package);
 void ODFPackageRelease(ODFPackage *package);
 int ODFPackageSave(ODFPackage *package, DFError **error);
diff --git a/DocFormats/filters/odf/src/ODFSheet.c b/DocFormats/filters/odf/src/ODFSheet.c
index 384d0d0..c2ea092 100644
--- a/DocFormats/filters/odf/src/ODFSheet.c
+++ b/DocFormats/filters/odf/src/ODFSheet.c
@@ -1,21 +1,25 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "ODFSheet.h"
 #include "DFDOM.h"
 #include "DFHashTable.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <stdlib.h>
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -26,7 +30,7 @@
 
 ODFStyle *ODFStyleNew()
 {
-    ODFStyle *style = (ODFStyle *)calloc(1,sizeof(ODFStyle));
+    ODFStyle *style = (ODFStyle *)xcalloc(1,sizeof(ODFStyle));
     style->retainCount = 1;
     return style;
 }
@@ -62,7 +66,7 @@
 
 ODFSheet *ODFSheetNew(DFDocument *stylesDoc, DFDocument *contentDoc)
 {
-    ODFSheet *sheet = (ODFSheet *)calloc(1,sizeof(ODFSheet));
+    ODFSheet *sheet = (ODFSheet *)xcalloc(1,sizeof(ODFSheet));
     sheet->retainCount = 1;
     sheet->stylesDoc = DFDocumentRetain(stylesDoc);
     sheet->contentDoc = DFDocumentRetain(contentDoc);
diff --git a/DocFormats/filters/odf/src/ODFSheet.h b/DocFormats/filters/odf/src/ODFSheet.h
index 8d1fff1..eee9697 100644
--- a/DocFormats/filters/odf/src/ODFSheet.h
+++ b/DocFormats/filters/odf/src/ODFSheet.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_ODFSheet_h
 #define DocFormats_ODFSheet_h
diff --git a/DocFormats/filters/odf/src/text/ODFText.c b/DocFormats/filters/odf/src/text/ODFText.c
new file mode 100644
index 0000000..0e13531
--- /dev/null
+++ b/DocFormats/filters/odf/src/text/ODFText.c
@@ -0,0 +1,37 @@
+// 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.
+
+#include "DFPlatform.h"
+#include "ODFText.h"
+
+DFDocument *ODFTextGet(DFStorage *concreteStorage, DFStorage *abstractStorage, const char *idPrefix, DFError **error)
+{
+    DFErrorFormat(error,"ODFTextGet: Not yet implemented");
+    return NULL;
+}
+
+int ODFTextPut(DFStorage *concreteStorage, DFStorage *abstractStorage, DFDocument *htmlDoc, const char *idPrefix, DFError **error)
+{
+    DFErrorFormat(error,"ODFTextPut: Not yet implemented");
+    return 0;
+}
+
+int ODFTextCreate(DFStorage *concreteStorage, DFStorage *abstractStorage, DFDocument *htmlDoc, DFError **error)
+{
+    DFErrorFormat(error,"ODFTextCreate: Not yet implemented");
+    return 0;
+}
diff --git a/DocFormats/filters/odf/src/text/ODFText.h b/DocFormats/filters/odf/src/text/ODFText.h
new file mode 100644
index 0000000..70486ab
--- /dev/null
+++ b/DocFormats/filters/odf/src/text/ODFText.h
@@ -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.
+
+#ifndef DocFormats_ODFText_h
+#define DocFormats_ODFText_h
+
+#include <DocFormats/DFError.h>
+#include <DocFormats/DFStorage.h>
+#include <DocFormats/DFXMLForward.h>
+
+DFDocument *ODFTextGet(DFStorage *concreteStorage, DFStorage *abstractStorage, const char *idPrefix, DFError **error);
+int ODFTextPut(DFStorage *concreteStorage, DFStorage *abstractStorage, DFDocument *htmlDoc, const char *idPrefix, DFError **error);
+int ODFTextCreate(DFStorage *concreteStorage, DFStorage *abstractStorage, DFDocument *htmlDoc, DFError **error);
+
+#endif
diff --git a/DocFormats/filters/odf/tests/ODFTests.c b/DocFormats/filters/odf/tests/ODFTests.c
index 9af04e8..a47f611 100644
--- a/DocFormats/filters/odf/tests/ODFTests.c
+++ b/DocFormats/filters/odf/tests/ODFTests.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFUnitTest.h"
 #include <stddef.h>
diff --git a/DocFormats/filters/ooxml/src/common/OOXMLTypedefs.h b/DocFormats/filters/ooxml/src/common/OOXMLTypedefs.h
index bf4c2b4..61d8cbb 100644
--- a/DocFormats/filters/ooxml/src/common/OOXMLTypedefs.h
+++ b/DocFormats/filters/ooxml/src/common/OOXMLTypedefs.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_OOXMLTypedefs_h
 #define DocFormats_OOXMLTypedefs_h
diff --git a/DocFormats/filters/ooxml/src/common/OPC.c b/DocFormats/filters/ooxml/src/common/OPC.c
index 724470c..9c7c1ed 100644
--- a/DocFormats/filters/ooxml/src/common/OPC.c
+++ b/DocFormats/filters/ooxml/src/common/OPC.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "OPC.h"
@@ -32,11 +35,11 @@
 
 static OPCRelationship *OPCRelationshipNew(const char *rId, const char *type, const char *target, int external)
 {
-    OPCRelationship *rel = (OPCRelationship *)calloc(1,sizeof(OPCRelationship));
+    OPCRelationship *rel = (OPCRelationship *)xcalloc(1,sizeof(OPCRelationship));
     rel->retainCount = 1;
-    rel->rId = (rId != NULL) ? strdup(rId) : NULL;
-    rel->type = (type != NULL) ? strdup(type) : NULL;
-    rel->target = (target != NULL) ? strdup(target) : NULL;
+    rel->rId = (rId != NULL) ? xstrdup(rId) : NULL;
+    rel->type = (type != NULL) ? xstrdup(type) : NULL;
+    rel->target = (target != NULL) ? xstrdup(target) : NULL;
     rel->external = external;
     return rel;
 }
@@ -73,7 +76,7 @@
 
 OPCRelationshipSet *OPCRelationshipSetNew(void)
 {
-    OPCRelationshipSet *set = (OPCRelationshipSet *)calloc(1,sizeof(OPCRelationshipSet));
+    OPCRelationshipSet *set = (OPCRelationshipSet *)xcalloc(1,sizeof(OPCRelationshipSet));
     set->relsById = DFHashTableNew((DFCopyFunction)OPCRelationshipRetain,(DFFreeFunction)OPCRelationshipRelease);
     set->relsByType = DFHashTableNew((DFCopyFunction)OPCRelationshipRetain,(DFFreeFunction)OPCRelationshipRelease);
     set->relsByDetail = DFHashTableNew((DFCopyFunction)OPCRelationshipRetain,(DFFreeFunction)OPCRelationshipRelease);
@@ -187,10 +190,10 @@
 
 OPCPart *OPCPartNew(const char *URI, const char *contentType)
 {
-    OPCPart *part = (OPCPart *)calloc(1,sizeof(OPCPart));
+    OPCPart *part = (OPCPart *)xcalloc(1,sizeof(OPCPart));
     part->retainCount = 1;
-    part->URI = (URI != NULL) ? strdup(URI) : NULL;
-    part->contentType = (contentType != NULL) ? strdup(contentType) : NULL;
+    part->URI = (URI != NULL) ? xstrdup(URI) : NULL;
+    part->contentType = (contentType != NULL) ? xstrdup(contentType) : NULL;
     part->relationships = OPCRelationshipSetNew();
     return part;
 }
@@ -225,9 +228,9 @@
 
 static OPCContentTypes *OPCContentTypesNew(void)
 {
-    OPCContentTypes *ct = (OPCContentTypes *)calloc(1,sizeof(OPCContentTypes));
-    ct->defaultsByExtension = DFHashTableNew((DFCopyFunction)strdup,free);
-    ct->overridesByPartName = DFHashTableNew((DFCopyFunction)strdup,free);
+    OPCContentTypes *ct = (OPCContentTypes *)xcalloc(1,sizeof(OPCContentTypes));
+    ct->defaultsByExtension = DFHashTableNew((DFCopyFunction)xstrdup,free);
+    ct->overridesByPartName = DFHashTableNew((DFCopyFunction)xstrdup,free);
     return ct;
 }
 
@@ -351,7 +354,7 @@
 
 static OPCPackage *OPCPackageNew(DFStorage *storage)
 {
-    OPCPackage *pkg = (OPCPackage *)calloc(1,sizeof(OPCPackage));
+    OPCPackage *pkg = (OPCPackage *)xcalloc(1,sizeof(OPCPackage));
     pkg->storage = DFStorageRetain(storage);
     pkg->contentTypes = OPCContentTypesNew();
     pkg->relationships = OPCRelationshipSetNew();
diff --git a/DocFormats/filters/ooxml/src/common/OPC.h b/DocFormats/filters/ooxml/src/common/OPC.h
index 76021c7..4f8d1bf 100644
--- a/DocFormats/filters/ooxml/src/common/OPC.h
+++ b/DocFormats/filters/ooxml/src/common/OPC.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_OPC_h
 #define DocFormats_OPC_h
diff --git a/DocFormats/filters/ooxml/src/word/CSSClassNames.c b/DocFormats/filters/ooxml/src/word/CSSClassNames.c
index d33f214..2c47bc6 100644
--- a/DocFormats/filters/ooxml/src/word/CSSClassNames.c
+++ b/DocFormats/filters/ooxml/src/word/CSSClassNames.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "CSSClassNames.h"
 #include "CSS.h"
@@ -26,6 +29,7 @@
 #include "WordStyles.h"
 #include "Word.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <stdlib.h>
 #include <string.h>
 
@@ -265,10 +269,10 @@
         const char *selector = allSelectors[i];
         char *className = CSSSelectorCopyClassName(selector);
         if (className == NULL)
-            className = strdup("");;
+            className = xstrdup("");;
 
-        SelectorList *item = (SelectorList *)calloc(1,sizeof(SelectorList));
-        item->selector = strdup(selector);
+        SelectorList *item = (SelectorList *)xcalloc(1,sizeof(SelectorList));
+        item->selector = xstrdup(selector);
         item->next = DFHashTableLookup(selectorsByClassName,className);
         DFHashTableAdd(selectorsByClassName,className,item);
         free(className);
@@ -395,7 +399,7 @@
 
 void CSSEnsureUnique(CSSSheet *styleSheet, DFDocument *htmlDoc, int creating)
 {
-    DFHashTable *repls = DFHashTableNew((DFCopyFunction)strdup,free);
+    DFHashTable *repls = DFHashTableNew((DFCopyFunction)xstrdup,free);
     determineReplacements(styleSheet,repls);
     replaceSelectorsInSheet(repls,styleSheet);
     replaceSelectorsInNode(repls,htmlDoc->root);
diff --git a/DocFormats/filters/ooxml/src/word/CSSClassNames.h b/DocFormats/filters/ooxml/src/word/CSSClassNames.h
index 2f29b62..b4a5b2b 100644
--- a/DocFormats/filters/ooxml/src/word/CSSClassNames.h
+++ b/DocFormats/filters/ooxml/src/word/CSSClassNames.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_CSSClassNames_h
 #define DocFormats_CSSClassNames_h
diff --git a/DocFormats/filters/ooxml/src/word/Word.c b/DocFormats/filters/ooxml/src/word/Word.c
index 1e06448..d5db0c7 100644
--- a/DocFormats/filters/ooxml/src/word/Word.c
+++ b/DocFormats/filters/ooxml/src/word/Word.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "Word.h"
@@ -23,7 +26,7 @@
 #include "DFZipFile.h"
 #include <stdlib.h>
 
-DFDocument *WordGet(DFStorage *concreteStorage, DFStorage *abstractStorage, DFError **error)
+DFDocument *WordGet(DFStorage *concreteStorage, DFStorage *abstractStorage, const char *idPrefix, DFError **error)
 {
     int ok = 0;
     WordPackage *wordPackage = NULL;
@@ -34,7 +37,7 @@
         goto end;
 
     htmlDoc = DFDocumentNew();
-    if (!WordConverterGet(htmlDoc,abstractStorage,"word",wordPackage,error))
+    if (!WordConverterGet(htmlDoc,abstractStorage,wordPackage,idPrefix,error))
         goto end;
 
     ok = 1;
@@ -50,18 +53,16 @@
     }
 }
 
-int WordPut(DFStorage *concreteStorage, DFStorage *abstractStorage, DFDocument *htmlDoc, DFError **error)
+int WordPut(DFStorage *concreteStorage, DFStorage *abstractStorage, DFDocument *htmlDoc, const char *idPrefix, DFError **error)
 {
     int ok = 0;
     WordPackage *wordPackage = NULL;
 
-    const char *idPrefix = "word";
-
     wordPackage = WordPackageOpenFrom(concreteStorage,error);
     if (wordPackage == NULL)
         goto end;
 
-    if (!WordConverterPut(htmlDoc,abstractStorage,idPrefix,wordPackage,error))
+    if (!WordConverterPut(htmlDoc,abstractStorage,wordPackage,idPrefix,error))
         goto end;
 
     if (!WordPackageSave(wordPackage,error))
@@ -79,19 +80,17 @@
     int ok = 0;
     WordPackage *wordPackage = NULL;
 
-    const char *idPrefix = "word";
-
     wordPackage = WordPackageOpenNew(concreteStorage,error);
     if (wordPackage == NULL)
         goto end;
 
-    // Change any id attributes starting with "word" or "odf" to a different prefix, so they
+    // Change any id attributes starting with "word" to a different prefix, so they
     // are not treated as references to nodes in the destination document. This is necessary
-    // if the HTML file was previously generated from a word or odf file, and we are creating
-    // a new word or odf file from it.
-    HTMLBreakBDTRefs(htmlDoc->docNode,idPrefix);
+    // if the HTML file was previously generated from a word file, and we are creating
+    // a new word file from it.
+    HTMLBreakBDTRefs(htmlDoc->docNode,"word");
 
-    if (!WordConverterPut(htmlDoc,abstractStorage,idPrefix,wordPackage,error))
+    if (!WordConverterPut(htmlDoc,abstractStorage,wordPackage,"word",error))
         goto end;
 
     if (!WordPackageSave(wordPackage,error))
diff --git a/DocFormats/filters/ooxml/src/word/Word.h b/DocFormats/filters/ooxml/src/word/Word.h
index e871754..98d05e4 100644
--- a/DocFormats/filters/ooxml/src/word/Word.h
+++ b/DocFormats/filters/ooxml/src/word/Word.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_Word_h
 #define DocFormats_Word_h
@@ -27,8 +30,8 @@
 
 CSSStyle *WordSetupTableGridStyle(CSSSheet *styleSheet, int *changed);
 
-DFDocument *WordGet(DFStorage *concreteStorage, DFStorage *abstractStorage, DFError **error);
-int WordPut(DFStorage *concreteStorage, DFStorage *abstractStorage, DFDocument *htmlDoc, DFError **error);
+DFDocument *WordGet(DFStorage *concreteStorage, DFStorage *abstractStorage, const char *idPrefix, DFError **error);
+int WordPut(DFStorage *concreteStorage, DFStorage *abstractStorage, DFDocument *htmlDoc, const char *idPrefix, DFError **error);
 int WordCreate(DFStorage *concreteStorage, DFStorage *abstractStorage, DFDocument *htmlDoc, DFError **error);
 int WordCollapseBookmarks(DFStorage *concreteStorage, DFError **error);
 int WordExpandBookmarks(DFStorage *concreteStorage, DFError **error);
diff --git a/DocFormats/filters/ooxml/src/word/WordCaption.c b/DocFormats/filters/ooxml/src/word/WordCaption.c
index 8379c16..4ac1149 100644
--- a/DocFormats/filters/ooxml/src/word/WordCaption.c
+++ b/DocFormats/filters/ooxml/src/word/WordCaption.c
@@ -1,18 +1,22 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "WordCaption.h"
+#include "DFPlatform.h"
 #include "DFCommon.h"
 #include <stdlib.h>
 
@@ -24,7 +28,7 @@
 
 WordCaption *WordCaptionNew(DFNode *element)
 {
-    WordCaption *caption = (WordCaption *)calloc(1,sizeof(WordCaption));
+    WordCaption *caption = (WordCaption *)xcalloc(1,sizeof(WordCaption));
     caption->retainCount = 1;
     caption->element = element;
     return caption;
diff --git a/DocFormats/filters/ooxml/src/word/WordCaption.h b/DocFormats/filters/ooxml/src/word/WordCaption.h
index 2110f99..8616a85 100644
--- a/DocFormats/filters/ooxml/src/word/WordCaption.h
+++ b/DocFormats/filters/ooxml/src/word/WordCaption.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordCaption_h
 #define DocFormats_WordCaption_h
diff --git a/DocFormats/filters/ooxml/src/word/WordConverter.c b/DocFormats/filters/ooxml/src/word/WordConverter.c
index 7e8f2ca..a68629e 100644
--- a/DocFormats/filters/ooxml/src/word/WordConverter.c
+++ b/DocFormats/filters/ooxml/src/word/WordConverter.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordConverter.h"
@@ -455,7 +458,7 @@
     int foundSeq = 0;
     int foundContent = 0;
     extractPrefixRecursive(node,counterName,result,&foundSeq,&foundContent);
-    char *str = strdup(result->data);
+    char *str = xstrdup(result->data);
     DFBufferRelease(result);
     return str;
 }
@@ -557,14 +560,13 @@
 //                                                                                                //
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
-static WordConverter *WordConverterNew(DFDocument *html, DFStorage *abstractStorage,
-                                       const char *idPrefix, WordPackage *package)
+static WordConverter *WordConverterNew(DFDocument *html, DFStorage *abstractStorage, WordPackage *package, const char *idPrefix)
 {
-    WordConverter *converter = (WordConverter *)calloc(1,sizeof(WordConverter));
+    WordConverter *converter = (WordConverter *)xcalloc(1,sizeof(WordConverter));
     converter->html = DFDocumentRetain(html);
     converter->abstractStorage = DFStorageRetain(abstractStorage);
     assert(DFStorageFormat(converter->abstractStorage) == DFFileFormatHTML);
-    converter->idPrefix = DFStrDup(idPrefix);
+    converter->idPrefix = (idPrefix != NULL) ? xstrdup(idPrefix) : xstrdup("word");
     converter->package = WordPackageRetain(package);
     converter->styles = WordSheetNew(converter->package->styles);
     converter->numbering = WordNumberingNew(converter->package);
@@ -573,7 +575,7 @@
     converter->objects = WordObjectsNew(converter->package);
     converter->footnotes = WordNoteGroupNewFootnotes(converter->package->footnotes);
     converter->endnotes = WordNoteGroupNewEndnotes(converter->package->endnotes);
-    converter->supportedContentTypes = DFHashTableNew((DFCopyFunction)strdup,free);
+    converter->supportedContentTypes = DFHashTableNew((DFCopyFunction)xstrdup,free);
     DFHashTableAdd(converter->supportedContentTypes,"jpg","image/jpeg");
     DFHashTableAdd(converter->supportedContentTypes,"jpeg","image/jpeg");
     DFHashTableAdd(converter->supportedContentTypes,"tif","image/tiff");
@@ -674,9 +676,7 @@
     return node;
 }
 
-int WordConverterGet(DFDocument *html, DFStorage *abstractStorage,
-                     const char *idPrefix, WordPackage *package,
-                     DFError **error)
+int WordConverterGet(DFDocument *html, DFStorage *abstractStorage, WordPackage *package, const char *idPrefix, DFError **error)
 {
     if (package->document == NULL) {
         DFErrorFormat(error,"document.xml not found");
@@ -692,7 +692,7 @@
     int haveFields = Word_simplifyFields(package);
     Word_mergeRuns(package);
 
-    WordConverter *converter = WordConverterNew(html,abstractStorage,idPrefix,package);
+    WordConverter *converter = WordConverterNew(html,abstractStorage,package,idPrefix);
     converter->haveFields = haveFields;
     WordAddNbsps(converter->package->document);
     WordFixLists(converter);
@@ -707,6 +707,7 @@
     get.conv = converter;
     DFNode *abstract = WordDocumentLens.get(&get,wordDocument);
     DFAppendChild(converter->html->docNode,abstract);
+    converter->html->root = abstract;
     Word_postProcessHTMLDoc(converter);
 
     HTMLAddExternalStyleSheet(converter->html,"reset.css");
@@ -777,7 +778,7 @@
 
         if (!DFStringEquals(wordType,htmlType)) {
             // Make a copy of numId, as it may be freed during the first call to DFHashTableRemove
-            char *numIdCopy = strdup(numId);
+            char *numIdCopy = xstrdup(numId);
             DFHashTableRemove(put->numIdByHtmlId,htmlId);
             DFHashTableRemove(put->htmlIdByNumId,numIdCopy);
             free(numIdCopy);
@@ -810,9 +811,7 @@
     }
 }
 
-int WordConverterPut(DFDocument *html, DFStorage *abstractStorage,
-                     const char *idPrefix, WordPackage *package,
-                     DFError **error)
+int WordConverterPut(DFDocument *html, DFStorage *abstractStorage, WordPackage *package, const char *idPrefix, DFError **error)
 {
     if (package->document == NULL) {
         DFErrorFormat(error,"document.xml not found");
@@ -828,7 +827,7 @@
     HTML_normalizeDocument(html);
     HTML_pushDownInlineProperties(html->docNode);
 
-    WordConverter *converter = WordConverterNew(html,abstractStorage,idPrefix,package);
+    WordConverter *converter = WordConverterNew(html,abstractStorage,package,idPrefix);
 
     // FIXME: Need a more reliable way of telling whether this is a new document or not - it could be that the
     // document already existed (with styles set up) but did not have any content
@@ -872,8 +871,8 @@
     WordPutData put;
     put.conv = converter;
     put.contentDoc = converter->package->document;
-    put.numIdByHtmlId = DFHashTableNew((DFCopyFunction)strdup,free);
-    put.htmlIdByNumId = DFHashTableNew((DFCopyFunction)strdup,free);
+    put.numIdByHtmlId = DFHashTableNew((DFCopyFunction)xstrdup,free);
+    put.htmlIdByNumId = DFHashTableNew((DFCopyFunction)xstrdup,free);
 
     // Make sure we update styles.xml from the CSS stylesheet *before* doing any conversion of the content,
     // since the latter requires a full mapping of CSS selectors to styleIds to be in place.
@@ -931,13 +930,13 @@
     char *resStyleId = NULL;
 
     if (!strcmp(selector,"table.Normal_Table"))
-        return strdup("TableNormal");
+        return xstrdup("TableNormal");
     if (!strcmp(selector,"table.Table_Grid"))
-        return strdup("TableGrid");
+        return xstrdup("TableGrid");
     if (!strcmp(selector,"span.Default_Paragraph_Font"))
-        return strdup("DefaultParagraphFont");
+        return xstrdup("DefaultParagraphFont");
     if (!strcmp(selector,"p.List_Paragraph"))
-        return strdup("ListParagraph");
+        return xstrdup("ListParagraph");
 
     int headingLevel = CSSSelectorHeadingLevel(selector);
     if (headingLevel != 0) {
@@ -953,23 +952,23 @@
     }
 
     if (!strcmp(selector,"span.Heading1Char"))
-        return strdup("Heading1Char");
+        return xstrdup("Heading1Char");
     if (!strcmp(selector,"span.Heading2Char"))
-        return strdup("Heading2Char");
+        return xstrdup("Heading2Char");
     if (!strcmp(selector,"span.Heading3Char"))
-        return strdup("Heading3Char");
+        return xstrdup("Heading3Char");
     if (!strcmp(selector,"span.Heading4Char"))
-        return strdup("Heading4Char");
+        return xstrdup("Heading4Char");
     if (!strcmp(selector,"span.Heading5Char"))
-        return strdup("Heading5Char");
+        return xstrdup("Heading5Char");
     if (!strcmp(selector,"span.Heading6Char"))
-        return strdup("Heading6Char");
+        return xstrdup("Heading6Char");
     if (!strcmp(selector,"span.Heading7Char"))
-        return strdup("Heading7Char");
+        return xstrdup("Heading7Char");
     if (!strcmp(selector,"span.Heading8Char"))
-        return strdup("Heading8Char");
+        return xstrdup("Heading8Char");
     if (!strcmp(selector,"span.Heading9Char"))
-        return strdup("Heading9Char");
+        return xstrdup("Heading9Char");
 
     char *className = CSSSelectorCopyClassName(selector);
     switch (CSSSelectorGetTag(selector)) {
@@ -1015,7 +1014,7 @@
     if (resStyleId == NULL) {
         // Note: selector here may start with . (i.e. applies to all elements)
         // FIXME: not covered by tests
-        resStyleId = strdup(selector);
+        resStyleId = xstrdup(selector);
     }
 
     return resStyleId;
diff --git a/DocFormats/filters/ooxml/src/word/WordConverter.h b/DocFormats/filters/ooxml/src/word/WordConverter.h
index c0565f2..e255ad2 100644
--- a/DocFormats/filters/ooxml/src/word/WordConverter.h
+++ b/DocFormats/filters/ooxml/src/word/WordConverter.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordConverter_h
 #define DocFormats_WordConverter_h
@@ -98,12 +101,8 @@
     CSSSheet *styleSheet;
 };
 
-int WordConverterGet(DFDocument *html, DFStorage *abstractStorage,
-                     const char *idPrefix, WordPackage *package,
-                     DFError **error);
-int WordConverterPut(DFDocument *html, DFStorage *abstractStorage,
-                     const char *idPrefix, WordPackage *package,
-                     DFError **error);
+int WordConverterGet(DFDocument *html, DFStorage *abstractStorage, WordPackage *package, const char *idPrefix, DFError **error);
+int WordConverterPut(DFDocument *html, DFStorage *abstractStorage, WordPackage *package, const char *idPrefix, DFError **error);
 void WordConverterWarning(WordConverter *converter, const char *format, ...) ATTRIBUTE_FORMAT(printf,2,3);
 
 char *WordStyleIdForStyle(CSSStyle *style);
diff --git a/DocFormats/filters/ooxml/src/word/WordGC.c b/DocFormats/filters/ooxml/src/word/WordGC.c
index 2698f71..0df299a 100644
--- a/DocFormats/filters/ooxml/src/word/WordGC.c
+++ b/DocFormats/filters/ooxml/src/word/WordGC.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordGC.h"
diff --git a/DocFormats/filters/ooxml/src/word/WordGC.h b/DocFormats/filters/ooxml/src/word/WordGC.h
index 03f10e4..246c0a6 100644
--- a/DocFormats/filters/ooxml/src/word/WordGC.h
+++ b/DocFormats/filters/ooxml/src/word/WordGC.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordGC_h
 #define DocFormats_WordGC_h
diff --git a/DocFormats/filters/ooxml/src/word/WordLists.c b/DocFormats/filters/ooxml/src/word/WordLists.c
index 8416fce..e9dee43 100644
--- a/DocFormats/filters/ooxml/src/word/WordLists.c
+++ b/DocFormats/filters/ooxml/src/word/WordLists.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLists.h"
@@ -54,7 +57,7 @@
 
 ListFrame *ListFrameNew(DFNode *element, ListFrame *parent, int numId, int ilvl, ListDimensions dimensions)
 {
-    ListFrame *frame = (ListFrame *)calloc(1,sizeof(ListFrame));
+    ListFrame *frame = (ListFrame *)xcalloc(1,sizeof(ListFrame));
     frame->element = element;
     frame->parent = parent;
     frame->numId = numId;
@@ -543,10 +546,10 @@
             continue;
 
         if (!createdHashTables) {
-            replacementNumIds = DFHashTableNew((DFCopyFunction)strdup,free);
-            itemNoByListKey = DFHashTableNew((DFCopyFunction)strdup,free);
-            lastNumIdByIlvl = DFHashTableNew((DFCopyFunction)strdup,free);
-            itemNoByIlvl = DFHashTableNew((DFCopyFunction)strdup,free);
+            replacementNumIds = DFHashTableNew((DFCopyFunction)xstrdup,free);
+            itemNoByListKey = DFHashTableNew((DFCopyFunction)xstrdup,free);
+            lastNumIdByIlvl = DFHashTableNew((DFCopyFunction)xstrdup,free);
+            itemNoByIlvl = DFHashTableNew((DFCopyFunction)xstrdup,free);
             createdHashTables = 1;
         }
 
@@ -572,7 +575,7 @@
         char *listKey = DFFormatString("%s:%s",numId,ilvl);
         char *itemNo = DFStrDup(DFHashTableLookup(itemNoByListKey,listKey));
         if (itemNo == NULL) {
-            itemNo = strdup("1");
+            itemNo = xstrdup("1");
 
             if ((levelStart != NULL) && (atoi(levelStart) > 1) && (atoi(ilvl) <= maxIlvl)) {
                 const char *prevNumId = DFHashTableLookup(lastNumIdByIlvl,ilvl);
diff --git a/DocFormats/filters/ooxml/src/word/WordLists.h b/DocFormats/filters/ooxml/src/word/WordLists.h
index 58a5ac0..9c146c3 100644
--- a/DocFormats/filters/ooxml/src/word/WordLists.h
+++ b/DocFormats/filters/ooxml/src/word/WordLists.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordLists_h
 #define DocFormats_WordLists_h
diff --git a/DocFormats/filters/ooxml/src/word/WordNotes.c b/DocFormats/filters/ooxml/src/word/WordNotes.c
index 06caa60..2e49c83 100644
--- a/DocFormats/filters/ooxml/src/word/WordNotes.c
+++ b/DocFormats/filters/ooxml/src/word/WordNotes.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordNotes.h"
@@ -264,7 +267,7 @@
 
 WordNote *WordNoteNew(DFNode *element, int noteId)
 {
-    WordNote *note = (WordNote *)calloc(1,sizeof(WordNote));
+    WordNote *note = (WordNote *)xcalloc(1,sizeof(WordNote));
     note->retainCount = 1;
     note->element = element;
     note->noteId = noteId;
@@ -313,7 +316,7 @@
     assert(doc != NULL);
     assert((noteTag == WORD_FOOTNOTE) || (noteTag == WORD_ENDNOTE));
 
-    WordNoteGroup *group = (WordNoteGroup *)calloc(1,sizeof(WordNoteGroup));
+    WordNoteGroup *group = (WordNoteGroup *)xcalloc(1,sizeof(WordNoteGroup));
     group->retainCount = 1;
     group->notesById = DFHashTableNew((DFCopyFunction)WordNoteRetain,(DFFreeFunction)WordNoteRelease);
     group->doc = DFDocumentRetain(doc);
diff --git a/DocFormats/filters/ooxml/src/word/WordNotes.h b/DocFormats/filters/ooxml/src/word/WordNotes.h
index 5e59bcc..ddeb106 100644
--- a/DocFormats/filters/ooxml/src/word/WordNotes.h
+++ b/DocFormats/filters/ooxml/src/word/WordNotes.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordNotes_h
 #define DocFormats_WordNotes_h
diff --git a/DocFormats/filters/ooxml/src/word/WordNumbering.c b/DocFormats/filters/ooxml/src/word/WordNumbering.c
index 76408e5..47b85d5 100644
--- a/DocFormats/filters/ooxml/src/word/WordNumbering.c
+++ b/DocFormats/filters/ooxml/src/word/WordNumbering.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordNumbering.h"
@@ -52,11 +55,11 @@
     if (ilvl == NULL)
         ilvl = "0";;
 
-    WordNumLevel *level = (WordNumLevel *)calloc(1,sizeof(WordNumLevel));
+    WordNumLevel *level = (WordNumLevel *)xcalloc(1,sizeof(WordNumLevel));
 
     level->ilvl = atoi(ilvl);
-    level->numFmt = (numFmt != NULL) ? strdup(numFmt) : NULL;
-    level->lvlText = (lvlText != NULL) ? strdup(lvlText) : NULL;
+    level->numFmt = (numFmt != NULL) ? xstrdup(numFmt) : NULL;
+    level->lvlText = (lvlText != NULL) ? xstrdup(lvlText) : NULL;
     level->element = element;
 
     return level;
@@ -116,8 +119,8 @@
 
 static WordAbstractNum *WordAbstractNumNew(const char *abstractNumId1, DFNode *element1)
 {
-    WordAbstractNum *abs = (WordAbstractNum *)calloc(1,sizeof(WordAbstractNum));
-    abs->abstractNumId = (abstractNumId1 != NULL) ? strdup(abstractNumId1) : NULL;
+    WordAbstractNum *abs = (WordAbstractNum *)xcalloc(1,sizeof(WordAbstractNum));
+    abs->abstractNumId = (abstractNumId1 != NULL) ? xstrdup(abstractNumId1) : NULL;
     abs->element = element1;
     abs->levels = DFHashTableNew(NULL,(DFFreeFunction)WordNumLevelFree);
     return abs;
@@ -148,8 +151,8 @@
 
 static WordConcreteNum *WordConcreteNumNew(const char *numId, DFNode *element, WordAbstractNum *abstractNum)
 {
-    WordConcreteNum *con = (WordConcreteNum *)calloc(1,sizeof(WordConcreteNum));
-    con->numId = (numId != NULL) ? strdup(numId) : NULL;
+    WordConcreteNum *con = (WordConcreteNum *)xcalloc(1,sizeof(WordConcreteNum));
+    con->numId = (numId != NULL) ? xstrdup(numId) : NULL;
     con->element = element;
     con->abstractNum = abstractNum;
     return con;
@@ -192,13 +195,13 @@
 
 WordNumbering *WordNumberingNew(WordPackage *package)
 {
-    WordNumbering *num = (WordNumbering *)calloc(1,sizeof(WordNumbering));
+    WordNumbering *num = (WordNumbering *)xcalloc(1,sizeof(WordNumbering));
     num->_package = WordPackageRetain(package);
     num->_abstractNums = DFHashTableNew(NULL,(DFFreeFunction)WordAbstractNumFree);
     num->_concreteNums = DFHashTableNew(NULL,(DFFreeFunction)WordConcreteNumFree);
     num->_nextAbstractId = 1;
     num->_nextConcreteId = 1;
-    num->_listStyleTypes = DFHashTableNew((DFCopyFunction)strdup,free);
+    num->_listStyleTypes = DFHashTableNew((DFCopyFunction)xstrdup,free);
 
     WordNumberingRegisterType(num,ListStyleTypeDecimal,"decimal");
     WordNumberingRegisterType(num,ListStyleTypeDecimalLeadingZero,"decimal-leading-zero");
diff --git a/DocFormats/filters/ooxml/src/word/WordNumbering.h b/DocFormats/filters/ooxml/src/word/WordNumbering.h
index 8d0e1cb..cc38b58 100644
--- a/DocFormats/filters/ooxml/src/word/WordNumbering.h
+++ b/DocFormats/filters/ooxml/src/word/WordNumbering.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordNumbering_h
 #define DocFormats_WordNumbering_h
diff --git a/DocFormats/filters/ooxml/src/word/WordObjects.c b/DocFormats/filters/ooxml/src/word/WordObjects.c
index 085a494..d4a9877 100644
--- a/DocFormats/filters/ooxml/src/word/WordObjects.c
+++ b/DocFormats/filters/ooxml/src/word/WordObjects.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "WordObjects.h"
 #include "WordPackage.h"
@@ -21,6 +24,7 @@
 #include "DFString.h"
 #include "DFHashTable.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <assert.h>
 #include <stdlib.h>
 
@@ -43,7 +47,7 @@
 
 WordObjects *WordObjectsNew(WordPackage *package)
 {
-    WordObjects *objects = (WordObjects *)calloc(1,sizeof(WordObjects));
+    WordObjects *objects = (WordObjects *)xcalloc(1,sizeof(WordObjects));
     objects->package = WordPackageRetain(package);
     objects->drawingsById = DFHashTableNew((DFCopyFunction)WordDrawingRetain,(DFFreeFunction)WordDrawingRelease);
     objects->bookmarksById = DFHashTableNew((DFCopyFunction)WordBookmarkRetain,(DFFreeFunction)WordBookmarkRelease);
diff --git a/DocFormats/filters/ooxml/src/word/WordObjects.h b/DocFormats/filters/ooxml/src/word/WordObjects.h
index 0a08525..6844bb3 100644
--- a/DocFormats/filters/ooxml/src/word/WordObjects.h
+++ b/DocFormats/filters/ooxml/src/word/WordObjects.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordObjects_h
 #define DocFormats_WordObjects_h
diff --git a/DocFormats/filters/ooxml/src/word/WordPackage.c b/DocFormats/filters/ooxml/src/word/WordPackage.c
index f6159fa..7595de6 100644
--- a/DocFormats/filters/ooxml/src/word/WordPackage.c
+++ b/DocFormats/filters/ooxml/src/word/WordPackage.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordPackage.h"
@@ -190,7 +193,7 @@
         return NULL;
 
     int ok = 0;
-    WordPackage *package = (WordPackage *)calloc(1,sizeof(WordPackage));
+    WordPackage *package = (WordPackage *)xcalloc(1,sizeof(WordPackage));
     package->retainCount = 1;
     package->opc = opc;
     package->documentPart = OPCPackagePartWithURI(package->opc,"/word/document.xml");
@@ -227,7 +230,7 @@
         return NULL;
 
     int ok = 0;
-    WordPackage *package = (WordPackage *)calloc(1,sizeof(WordPackage));
+    WordPackage *package = (WordPackage *)xcalloc(1,sizeof(WordPackage));
     package->retainCount = 1;
     package->opc = opc;
 
diff --git a/DocFormats/filters/ooxml/src/word/WordPackage.h b/DocFormats/filters/ooxml/src/word/WordPackage.h
index eaef4d0..df318ef 100644
--- a/DocFormats/filters/ooxml/src/word/WordPackage.h
+++ b/DocFormats/filters/ooxml/src/word/WordPackage.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordPackage_h
 #define DocFormats_WordPackage_h
diff --git a/DocFormats/filters/ooxml/src/word/WordSection.c b/DocFormats/filters/ooxml/src/word/WordSection.c
index af866dc..97ca444 100644
--- a/DocFormats/filters/ooxml/src/word/WordSection.c
+++ b/DocFormats/filters/ooxml/src/word/WordSection.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "WordSection.h"
 #include "WordStyles.h"
@@ -18,6 +21,7 @@
 #include "CSSLength.h"
 #include "DFString.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <math.h>
 #include <stdlib.h>
 
@@ -29,7 +33,7 @@
 
 WordSection *WordSectionNew(void)
 {
-    WordSection *section = (WordSection *)calloc(1,sizeof(WordSection));
+    WordSection *section = (WordSection *)xcalloc(1,sizeof(WordSection));
     section->pageWidth = A4_WIDTH_TWIPS;
     section->pageHeight = A4_HEIGHT_TWIPS;
     section->leftMargin = 0;
diff --git a/DocFormats/filters/ooxml/src/word/WordSection.h b/DocFormats/filters/ooxml/src/word/WordSection.h
index 058ce5c..0cbffa5 100644
--- a/DocFormats/filters/ooxml/src/word/WordSection.h
+++ b/DocFormats/filters/ooxml/src/word/WordSection.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordSection_h
 #define DocFormats_WordSection_h
diff --git a/DocFormats/filters/ooxml/src/word/WordSettings.c b/DocFormats/filters/ooxml/src/word/WordSettings.c
index 2c17786..6ada764 100644
--- a/DocFormats/filters/ooxml/src/word/WordSettings.c
+++ b/DocFormats/filters/ooxml/src/word/WordSettings.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordSettings.h"
diff --git a/DocFormats/filters/ooxml/src/word/WordSettings.h b/DocFormats/filters/ooxml/src/word/WordSettings.h
index bb20e01..059aa96 100644
--- a/DocFormats/filters/ooxml/src/word/WordSettings.h
+++ b/DocFormats/filters/ooxml/src/word/WordSettings.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordSettings_h
 #define DocFormats_WordSettings_h
diff --git a/DocFormats/filters/ooxml/src/word/WordSheet.c b/DocFormats/filters/ooxml/src/word/WordSheet.c
index 74f9fdc..8c9231c 100644
--- a/DocFormats/filters/ooxml/src/word/WordSheet.c
+++ b/DocFormats/filters/ooxml/src/word/WordSheet.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "WordSheet.h"
 #include "DFDOM.h"
@@ -18,6 +21,7 @@
 #include "DFString.h"
 #include "Word.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
@@ -29,7 +33,7 @@
 
 char *WordStyleNameToClassName(const char *name)
 {
-    char *className = strdup(name);
+    char *className = xstrdup(name);
     for (char *c = className; *c != '\0'; c++) {
         if (*c == ' ')
             *c = '_';
@@ -39,7 +43,7 @@
 
 char *WordStyleNameFromClassName(const char *name)
 {
-    char *className = strdup(name);
+    char *className = xstrdup(name);
     for (char *c = className; *c != '\0'; c++) {
         if (*c == '_')
             *c = ' ';
@@ -60,16 +64,16 @@
     assert(styleId != NULL);
     assert(element->tag == WORD_STYLE);
 
-    WordStyle *style = (WordStyle *)calloc(1,sizeof(WordStyle));
+    WordStyle *style = (WordStyle *)xcalloc(1,sizeof(WordStyle));
     style->retainCount = 1;
     style->element = element;
-    style->type = (type != NULL) ? strdup(type) : NULL;
-    style->styleId = (styleId != NULL) ? strdup(styleId) : NULL;
+    style->type = (type != NULL) ? xstrdup(type) : NULL;
+    style->styleId = (styleId != NULL) ? xstrdup(styleId) : NULL;
     style->ident = WordSheetIdentForType(style->type,style->styleId);
     style->basedOn = DFStrDup(DFGetChildAttribute(style->element,WORD_BASEDON,WORD_VAL));
     DFNode *pPr = DFChildWithTag(style->element,WORD_PPR);
     style->outlineLvl = DFStrDup(DFGetChildAttribute(pPr,WORD_OUTLINELVL,WORD_VAL));
-    style->name = strdup(name);
+    style->name = xstrdup(name);
 
     return style;
 }
@@ -121,7 +125,7 @@
 
 WordSheet *WordSheetNew(DFDocument *doc)
 {
-    WordSheet *sheet = (WordSheet *)calloc(1,sizeof(WordSheet));
+    WordSheet *sheet = (WordSheet *)xcalloc(1,sizeof(WordSheet));
 
     sheet->stylesByIdent = DFHashTableNew((DFCopyFunction)WordStyleRetain,(DFFreeFunction)WordStyleRelease);
     sheet->stylesByName = DFHashTableNew((DFCopyFunction)WordStyleRetain,(DFFreeFunction)WordStyleRelease);
@@ -207,7 +211,7 @@
     DFSetAttribute(nameNode,WORD_VAL,name);
 
     WordStyle *style = WordStyleNew(element,type,styleId,name);
-    style->selector = strdup(selector);
+    style->selector = xstrdup(selector);
     DFHashTableAdd(sheet->stylesByIdent,style->ident,style);
     DFHashTableAdd(sheet->stylesByName,style->name,style);
     DFHashTableAdd(sheet->stylesBySelector,style->selector,style);
@@ -266,7 +270,7 @@
 
         // Compute inherited properties
         WordStyle *ancestor = style;
-        DFHashTable *visited = DFHashTableNew((DFCopyFunction)strdup,free);
+        DFHashTable *visited = DFHashTableNew((DFCopyFunction)xstrdup,free);
         while ((ancestor != NULL) && (DFHashTableLookup(visited,ancestor->ident) == NULL)) {
             DFHashTableAdd(visited,ancestor->ident,"");
 
diff --git a/DocFormats/filters/ooxml/src/word/WordSheet.h b/DocFormats/filters/ooxml/src/word/WordSheet.h
index 0a08714..da6a8ce 100644
--- a/DocFormats/filters/ooxml/src/word/WordSheet.h
+++ b/DocFormats/filters/ooxml/src/word/WordSheet.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordSheet_h
 #define DocFormats_WordSheet_h
diff --git a/DocFormats/filters/ooxml/src/word/WordStyles.c b/DocFormats/filters/ooxml/src/word/WordStyles.c
index c7e5e8a..5358d6d 100644
--- a/DocFormats/filters/ooxml/src/word/WordStyles.c
+++ b/DocFormats/filters/ooxml/src/word/WordStyles.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordStyles.h"
@@ -232,7 +235,7 @@
             if ((style->tag != HTML_P) && (style->tag != HTML_SPAN) && (style->tag != HTML_TABLE)) {
                 CSSStyle *parentStyle = CSSSheetLookupElement(converter->styleSheet,style->elementName,NULL,0,0);
                 if ((parentStyle != NULL) && !parentStyle->latent)
-                    parentSelector = strdup(style->elementName);
+                    parentSelector = xstrdup(style->elementName);
             }
         }
     }
@@ -482,7 +485,7 @@
         }
     }
     replaceChildrenFromArray(concrete,children,WordSectPr_Children);
-    for (long i = DFArrayCount(extra)-1; i >= 0; i--) {
+    for (long i = (long)(DFArrayCount(extra)-1); i >= 0; i--) {
         DFNode *child = DFArrayItemAt(extra,i);
         DFInsertBefore(concrete,child,concrete->first);
     }
@@ -720,13 +723,13 @@
         return WordStyleNameFromClassName(style->className);
 
     switch (style->tag) {
-        case HTML_H1: return strdup("heading 1");
-        case HTML_H2: return strdup("heading 2");
-        case HTML_H3: return strdup("heading 3");
-        case HTML_H4: return strdup("heading 4");
-        case HTML_H5: return strdup("heading 5");
-        case HTML_H6: return strdup("heading 6");
-        case HTML_FIGURE: return strdup("Figure");
+        case HTML_H1: return xstrdup("heading 1");
+        case HTML_H2: return xstrdup("heading 2");
+        case HTML_H3: return xstrdup("heading 3");
+        case HTML_H4: return xstrdup("heading 4");
+        case HTML_H5: return xstrdup("heading 5");
+        case HTML_H6: return xstrdup("heading 6");
+        case HTML_FIGURE: return xstrdup("Figure");
     }
 
     return NULL;
@@ -814,7 +817,7 @@
         char *styleId = WordStyleIdForStyle(style);
         char *name = WordStyleNameForStyle(style);
         if (name == NULL)
-            name = strdup(styleId);;
+            name = xstrdup(styleId);;
         WordStyle *wordStyle = WordSheetAddStyle(sheet,familyStr,styleId,name,selector);
         DFCreateChildElement(wordStyle->element,WORD_QFORMAT);
         free(styleId);
diff --git a/DocFormats/filters/ooxml/src/word/WordStyles.h b/DocFormats/filters/ooxml/src/word/WordStyles.h
index b5cbb1b..19370b7 100644
--- a/DocFormats/filters/ooxml/src/word/WordStyles.h
+++ b/DocFormats/filters/ooxml/src/word/WordStyles.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordStyles_h
 #define DocFormats_WordStyles_h
diff --git a/DocFormats/filters/ooxml/src/word/WordTheme.c b/DocFormats/filters/ooxml/src/word/WordTheme.c
index dbd9cc3..d64fc8e 100644
--- a/DocFormats/filters/ooxml/src/word/WordTheme.c
+++ b/DocFormats/filters/ooxml/src/word/WordTheme.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordTheme.h"
@@ -29,7 +32,7 @@
 
 WordTheme *WordThemeNew(WordPackage *package)
 {
-    WordTheme *theme = (WordTheme *)calloc(1,sizeof(WordTheme));
+    WordTheme *theme = (WordTheme *)xcalloc(1,sizeof(WordTheme));
 
     DFDocument *doc = package->theme;
     if (doc == NULL)
@@ -46,8 +49,8 @@
 
     const char *majorFont = DFGetChildAttribute(majorFontElem,DML_MAIN_LATIN,NULL_TYPEFACE);
     const char *minorFont = DFGetChildAttribute(minorFontElem,DML_MAIN_LATIN,NULL_TYPEFACE);
-    theme->majorFont = (majorFont != NULL) ? strdup(majorFont) : NULL;
-    theme->minorFont = (minorFont != NULL) ? strdup(minorFont) : NULL;
+    theme->majorFont = (majorFont != NULL) ? xstrdup(majorFont) : NULL;
+    theme->minorFont = (minorFont != NULL) ? xstrdup(minorFont) : NULL;
 
     return theme;
 }
diff --git a/DocFormats/filters/ooxml/src/word/WordTheme.h b/DocFormats/filters/ooxml/src/word/WordTheme.h
index 7bfc4fc..96378f7 100644
--- a/DocFormats/filters/ooxml/src/word/WordTheme.h
+++ b/DocFormats/filters/ooxml/src/word/WordTheme.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordTheme_h
 #define DocFormats_WordTheme_h
diff --git a/DocFormats/filters/ooxml/src/word/WordWhitespace.c b/DocFormats/filters/ooxml/src/word/WordWhitespace.c
index 5769cf9..ade5d5c 100644
--- a/DocFormats/filters/ooxml/src/word/WordWhitespace.c
+++ b/DocFormats/filters/ooxml/src/word/WordWhitespace.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordWhitespace.h"
diff --git a/DocFormats/filters/ooxml/src/word/WordWhitespace.h b/DocFormats/filters/ooxml/src/word/WordWhitespace.h
index 5b9d1aa..97668b6 100644
--- a/DocFormats/filters/ooxml/src/word/WordWhitespace.h
+++ b/DocFormats/filters/ooxml/src/word/WordWhitespace.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordWhitespace_h
 #define DocFormats_WordWhitespace_h
diff --git a/DocFormats/filters/ooxml/src/word/formatting/WordCommonPr.c b/DocFormats/filters/ooxml/src/word/formatting/WordCommonPr.c
index 0578e3b..dd50fd5 100644
--- a/DocFormats/filters/ooxml/src/word/formatting/WordCommonPr.c
+++ b/DocFormats/filters/ooxml/src/word/formatting/WordCommonPr.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordCommonPr.h"
@@ -126,7 +129,7 @@
     if ((color != NULL) && isRRGGBB(color))
         value = DFFormatString("#%s",color);
     else
-        value = strdup("black");
+        value = xstrdup("black");
     CSSPut(properties,colorName,value);
     free(value);
 
diff --git a/DocFormats/filters/ooxml/src/word/formatting/WordCommonPr.h b/DocFormats/filters/ooxml/src/word/formatting/WordCommonPr.h
index 44d6707..0b5fdba 100644
--- a/DocFormats/filters/ooxml/src/word/formatting/WordCommonPr.h
+++ b/DocFormats/filters/ooxml/src/word/formatting/WordCommonPr.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordCommonPr_h
 #define DocFormats_WordCommonPr_h
diff --git a/DocFormats/filters/ooxml/src/word/formatting/WordNumPr.c b/DocFormats/filters/ooxml/src/word/formatting/WordNumPr.c
index 21d0deb..b8e431d 100644
--- a/DocFormats/filters/ooxml/src/word/formatting/WordNumPr.c
+++ b/DocFormats/filters/ooxml/src/word/formatting/WordNumPr.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordNumPr.h"
@@ -75,7 +78,7 @@
 
     if ((result->len > 0) && !endsWithWhitespace)
         DFBufferFormat(result," \" \"");
-    char *str = strdup(result->data);
+    char *str = xstrdup(result->data);
     DFBufferRelease(result);
     return str;
 }
@@ -134,7 +137,7 @@
 
 static WordNumInfo *WordNumInfoNew(void)
 {
-    return (WordNumInfo *)calloc(1,sizeof(WordNumInfo));
+    return (WordNumInfo *)xcalloc(1,sizeof(WordNumInfo));
 }
 
 static void WordNumInfoFree(WordNumInfo *info)
@@ -182,9 +185,9 @@
                     if (DFStringEquals(part->value,elementName)) {
                         free(info->cssType);
                         if (part->arg != NULL)
-                            info->cssType = strdup(part->arg);
+                            info->cssType = xstrdup(part->arg);
                         else
-                            info->cssType = strdup("decimal");
+                            info->cssType = xstrdup("decimal");
                     }
                     if ((strlen(part->value) == 2) && (part->value[0] == 'h'))
                         DFBufferFormat(format,"%%%c",part->value[1]);
@@ -203,7 +206,7 @@
                 format->len--;
             }
 
-            info->cssLvlText = strdup(format->data);
+            info->cssLvlText = xstrdup(format->data);
             free(elementName);
             DFBufferRelease(format);
         }
@@ -221,8 +224,8 @@
                 if (concreteNum != NULL) {
                     WordNumLevel *level = WordConcreteNumGetLevel(concreteNum,atoi(ilvl));
                     if (level != NULL) {
-                        info->wordNumId = strdup(numId);
-                        info->wordIlvl = strdup(ilvl);
+                        info->wordNumId = xstrdup(numId);
+                        info->wordIlvl = xstrdup(ilvl);
                         info->wordLevel = level;
 
                         int ilvlValue = atoi(ilvl);
@@ -275,8 +278,8 @@
             CSSStyle *style = CSSSheetLookupSelector(cssSheet,allSelectors[i],0,0);
             if ((style->headingLevel >= 1) && (style->headingLevel <= 6)) {
                 int level = style->headingLevel - 1;
-                SelectorList *item = (SelectorList *)calloc(1,sizeof(SelectorList));
-                item->selector = strdup(style->selector);
+                SelectorList *item = (SelectorList *)xcalloc(1,sizeof(SelectorList));
+                item->selector = xstrdup(style->selector);
                 item->next = DFHashTableLookupInt(selectorsByLevel,level);
                 DFHashTableAddInt(selectorsByLevel,level,item);
             }
@@ -315,13 +318,13 @@
                     info = WordNumInfoNew();
                     DFHashTableAdd(infoByStyleId,style->selector,info);
                 }
-                curType = strdup(info->cssType);
-                curLvlText = strdup(info->cssLvlText);
+                curType = xstrdup(info->cssType);
+                curLvlText = xstrdup(info->cssLvlText);
             }
 
 
             if (curType == NULL)
-                curType = (prevType != NULL) ? strdup(prevType) : strdup("decimal");
+                curType = (prevType != NULL) ? xstrdup(prevType) : xstrdup("decimal");
 
             if ((curLvlText == NULL) || (strlen(curLvlText) == 0)) {
                 free(curLvlText);
@@ -340,7 +343,7 @@
                 assert(info->wordLevel != NULL);
                 free(info->wordNumId);
                 free(info->wordIlvl);
-                info->wordNumId = strdup(concreteNum->numId);
+                info->wordNumId = xstrdup(concreteNum->numId);
                 info->wordIlvl = DFFormatString("%d",i);
             }
 
diff --git a/DocFormats/filters/ooxml/src/word/formatting/WordNumPr.h b/DocFormats/filters/ooxml/src/word/formatting/WordNumPr.h
index 5ccbbbf..93ce768 100644
--- a/DocFormats/filters/ooxml/src/word/formatting/WordNumPr.h
+++ b/DocFormats/filters/ooxml/src/word/formatting/WordNumPr.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordNumPr_h
 #define DocFormats_WordNumPr_h
diff --git a/DocFormats/filters/ooxml/src/word/formatting/WordPPr.c b/DocFormats/filters/ooxml/src/word/formatting/WordPPr.c
index a40da92..022ba5e 100644
--- a/DocFormats/filters/ooxml/src/word/formatting/WordPPr.c
+++ b/DocFormats/filters/ooxml/src/word/formatting/WordPPr.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordPPr.h"
diff --git a/DocFormats/filters/ooxml/src/word/formatting/WordPPr.h b/DocFormats/filters/ooxml/src/word/formatting/WordPPr.h
index 6572992..4961bce 100644
--- a/DocFormats/filters/ooxml/src/word/formatting/WordPPr.h
+++ b/DocFormats/filters/ooxml/src/word/formatting/WordPPr.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordPPr_h
 #define DocFormats_WordPPr_h
diff --git a/DocFormats/filters/ooxml/src/word/formatting/WordRPr.c b/DocFormats/filters/ooxml/src/word/formatting/WordRPr.c
index 551d145..a2f13a1 100644
--- a/DocFormats/filters/ooxml/src/word/formatting/WordRPr.c
+++ b/DocFormats/filters/ooxml/src/word/formatting/WordRPr.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordRPr.h"
diff --git a/DocFormats/filters/ooxml/src/word/formatting/WordRPr.h b/DocFormats/filters/ooxml/src/word/formatting/WordRPr.h
index 376eba4..487c5d8 100644
--- a/DocFormats/filters/ooxml/src/word/formatting/WordRPr.h
+++ b/DocFormats/filters/ooxml/src/word/formatting/WordRPr.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordRPr_h
 #define DocFormats_WordRPr_h
diff --git a/DocFormats/filters/ooxml/src/word/formatting/WordTblPr.c b/DocFormats/filters/ooxml/src/word/formatting/WordTblPr.c
index bb398b3..5ce603f 100644
--- a/DocFormats/filters/ooxml/src/word/formatting/WordTblPr.c
+++ b/DocFormats/filters/ooxml/src/word/formatting/WordTblPr.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordTblPr.h"
@@ -104,13 +107,13 @@
         // Units: 1/50ths of a percent
         double pct = atoi(width)/50.0;
         char buf[100];
-        return strdup(DFFormatDoublePct(buf,100,pct));
+        return xstrdup(DFFormatDoublePct(buf,100,pct));
     }
     else if (!strcmp(type,"dxa") && (WordSectionContentWidth(section) > 0)) {
         // Units: 1/20ths of a point
         double pct = 100.0*atoi(width)/(double)WordSectionContentWidth(section);
         char buf[100];
-        return strdup(DFFormatDoublePct(buf,100,pct));
+        return xstrdup(DFFormatDoublePct(buf,100,pct));
     }
     return NULL;
 }
@@ -205,7 +208,7 @@
         double pts = atoi(w)/20.0;
         char *name = DFFormatString("padding-%s",side);
         char buf[100];
-        char *value = strdup(DFFormatDoublePt(buf,100,pts));
+        char *value = xstrdup(DFFormatDoublePt(buf,100,pts));
         CSSPut(properties,name,value);
         free(name);
         free(value);
diff --git a/DocFormats/filters/ooxml/src/word/formatting/WordTblPr.h b/DocFormats/filters/ooxml/src/word/formatting/WordTblPr.h
index a394dc6..a2a1926 100644
--- a/DocFormats/filters/ooxml/src/word/formatting/WordTblPr.h
+++ b/DocFormats/filters/ooxml/src/word/formatting/WordTblPr.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordTblPr_h
 #define DocFormats_WordTblPr_h
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordBlockLevel.c b/DocFormats/filters/ooxml/src/word/lenses/WordBlockLevel.c
index fe71ff2..c7857ae 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordBlockLevel.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordBlockLevel.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordBody.c b/DocFormats/filters/ooxml/src/word/lenses/WordBody.c
index 6c8b92f..a1f920e 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordBody.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordBody.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordBookmark.c b/DocFormats/filters/ooxml/src/word/lenses/WordBookmark.c
index fcd2f53..56d8a02 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordBookmark.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordBookmark.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "WordBookmark.h"
 #include "WordLenses.h"
@@ -23,6 +26,7 @@
 #include "DFHTML.h"
 #include "DFString.h"
 #include "DFCommon.h"
+#include "DFPlatform.h"
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
@@ -68,10 +72,10 @@
 
 WordBookmark *WordBookmarkNew(const char *bookmarkId1, const char *bookmarkName1)
 {
-    WordBookmark *bookmark = (WordBookmark *)calloc(1,sizeof(WordBookmark));
+    WordBookmark *bookmark = (WordBookmark *)xcalloc(1,sizeof(WordBookmark));
     bookmark->retainCount = 1;
-    bookmark->bookmarkId = (bookmarkId1 != NULL) ? strdup(bookmarkId1) : NULL;
-    bookmark->bookmarkName = (bookmarkName1 != NULL) ? strdup(bookmarkName1) : NULL;
+    bookmark->bookmarkId = (bookmarkId1 != NULL) ? xstrdup(bookmarkId1) : NULL;
+    bookmark->bookmarkName = (bookmarkName1 != NULL) ? xstrdup(bookmarkName1) : NULL;
     bookmark->type = WordBookmarkUnknown;
     return bookmark;
 }
@@ -160,7 +164,7 @@
             DFNodeTextToBuffer(child,buffer);
     }
     free(bookmark->label);
-    bookmark->label = strdup(buffer->data);
+    bookmark->label = xstrdup(buffer->data);
     DFBufferRelease(buffer);
 }
 
@@ -438,7 +442,7 @@
 
 WordRawBookmark *WordRawBookmarkNew(void)
 {
-    WordRawBookmark *bookmark = (WordRawBookmark *)calloc(1,sizeof(WordRawBookmark));
+    WordRawBookmark *bookmark = (WordRawBookmark *)xcalloc(1,sizeof(WordRawBookmark));
     bookmark->startOffset = -1;
     bookmark->endOffset = -1;
     return bookmark;
@@ -532,8 +536,8 @@
             case WORD_BOOKMARKEND: {
                 DFArray *startElements = DFArrayNew(NULL,NULL);
                 DFArray *endElements = DFArrayNew(NULL,NULL);
-                DFHashTable *startIds = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
-                DFHashTable *endIds = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+                DFHashTable *startIds = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
+                DFHashTable *endIds = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
                 DFNode *n;
                 for (n = child;
                      (n != NULL) && ((n->tag == WORD_BOOKMARKSTART) || (n->tag == WORD_BOOKMARKEND));
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordBookmark.h b/DocFormats/filters/ooxml/src/word/lenses/WordBookmark.h
index 18f2d87..ce66df4 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordBookmark.h
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordBookmark.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordBookmark_h
 #define DocFormats_WordBookmark_h
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordChange.c b/DocFormats/filters/ooxml/src/word/lenses/WordChange.c
index 484131c..861706a 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordChange.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordChange.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordDocument.c b/DocFormats/filters/ooxml/src/word/lenses/WordDocument.c
index 8c2ce78..01bb883 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordDocument.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordDocument.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordDrawing.c b/DocFormats/filters/ooxml/src/word/lenses/WordDrawing.c
index 0d53286..77ef362 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordDrawing.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordDrawing.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordDrawing.h"
@@ -68,7 +71,7 @@
 
 static ImageInfo *ImageInfoNew(const char *rId, double widthPts, double heightPts)
 {
-    ImageInfo *info = (ImageInfo *)calloc(1,sizeof(ImageInfo));
+    ImageInfo *info = (ImageInfo *)xcalloc(1,sizeof(ImageInfo));
     info->rId = DFStrDup(rId);
     info->widthPts = widthPts;
     info->heightPts = heightPts;
@@ -144,9 +147,9 @@
 
 WordDrawing *WordDrawingNew(const char *drawingId)
 {
-    WordDrawing *drawing = (WordDrawing *)calloc(1,sizeof(WordDrawing));
+    WordDrawing *drawing = (WordDrawing *)xcalloc(1,sizeof(WordDrawing));
     drawing->retainCount = 1;
-    drawing->drawingId = strdup(drawingId);
+    drawing->drawingId = xstrdup(drawingId);
     return drawing;
 }
 
@@ -335,7 +338,7 @@
     if (paths == NULL)
         return NULL;;
 
-    DFHashTable *existingPaths = DFHashTableNew((DFCopyFunction)strdup,free);
+    DFHashTable *existingPaths = DFHashTableNew((DFCopyFunction)xstrdup,free);
     for (int i = 0; paths[i]; i++) {
         const char *path = paths[i];
         char *lowerPath = DFLowerCase(path);
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordDrawing.h b/DocFormats/filters/ooxml/src/word/lenses/WordDrawing.h
index 6b8b5a3..c10c661 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordDrawing.h
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordDrawing.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordDrawing_h
 #define DocFormats_WordDrawing_h
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordEquation.c b/DocFormats/filters/ooxml/src/word/lenses/WordEquation.c
index d56b9e2..79694b3 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordEquation.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordEquation.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordField.c b/DocFormats/filters/ooxml/src/word/lenses/WordField.c
index 9235a45..5ba51ac 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordField.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordField.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordField.h"
@@ -34,7 +37,7 @@
 const char **Word_parseField(const char *str)
 {
     size_t len = strlen(str);
-    DFArray *components = DFArrayNew((DFCopyFunction)strdup,free);
+    DFArray *components = DFArrayNew((DFCopyFunction)xstrdup,free);
 
     size_t start = 0;
     int inString = 0;
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordField.h b/DocFormats/filters/ooxml/src/word/lenses/WordField.h
index a2c2e74..3b5647b 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordField.h
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordField.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordField_h
 #define DocFormats_WordField_h
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordHyperlink.c b/DocFormats/filters/ooxml/src/word/lenses/WordHyperlink.c
index 7d19742..00ee642 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordHyperlink.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordHyperlink.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordLenses.c b/DocFormats/filters/ooxml/src/word/lenses/WordLenses.c
index 2137762..994f45a 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordLenses.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordLenses.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordLenses.h b/DocFormats/filters/ooxml/src/word/lenses/WordLenses.h
index 0337bea..fd13d5f 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordLenses.h
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordLenses.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordLenses_h
 #define DocFormats_WordLenses_h
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordParagraph.c b/DocFormats/filters/ooxml/src/word/lenses/WordParagraph.c
index 0a836d0..5801221 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordParagraph.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordParagraph.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
@@ -192,7 +195,7 @@
     // FIXME: Won't work with Word documents created in non-English languages
     if ((selector != NULL) && (abstract->tag == HTML_P) && DFStringEquals(className,"Caption")) {
         free(selector);
-        selector = strdup("caption");
+        selector = xstrdup("caption");
     }
 
     if (selector != NULL) {
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordParagraphContent.c b/DocFormats/filters/ooxml/src/word/lenses/WordParagraphContent.c
index 19e86f2..5bc9e57 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordParagraphContent.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordParagraphContent.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordRun.c b/DocFormats/filters/ooxml/src/word/lenses/WordRun.c
index 86b21be..9496dba 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordRun.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordRun.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordRunContent.c b/DocFormats/filters/ooxml/src/word/lenses/WordRunContent.c
index 784e145..0cc5a09 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordRunContent.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordRunContent.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordSmartTag.c b/DocFormats/filters/ooxml/src/word/lenses/WordSmartTag.c
index 5f527d0..df74119 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordSmartTag.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordSmartTag.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
diff --git a/DocFormats/filters/ooxml/src/word/lenses/WordTable.c b/DocFormats/filters/ooxml/src/word/lenses/WordTable.c
index 36f51d5..6f69130 100644
--- a/DocFormats/filters/ooxml/src/word/lenses/WordTable.c
+++ b/DocFormats/filters/ooxml/src/word/lenses/WordTable.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordLenses.h"
@@ -40,7 +43,7 @@
 
 static ConcreteInfo *ConcreteInfoNew(void)
 {
-    ConcreteInfo *info = (ConcreteInfo *)calloc(1,sizeof(ConcreteInfo));
+    ConcreteInfo *info = (ConcreteInfo *)xcalloc(1,sizeof(ConcreteInfo));
     info->tableProperties = CSSPropertiesNew();
     info->cellProperties = CSSPropertiesNew();
     return info;
diff --git a/DocFormats/filters/ooxml/tests/word/WordPlain.c b/DocFormats/filters/ooxml/tests/word/WordPlain.c
index 9857817..dfb13a4 100644
--- a/DocFormats/filters/ooxml/tests/word/WordPlain.c
+++ b/DocFormats/filters/ooxml/tests/word/WordPlain.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "WordPlain.h"
@@ -84,7 +87,7 @@
         if (strcmp(type,"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"))
             continue;
 
-        result = strdup(target);
+        result = xstrdup(target);
         ok = 1;
         break;
     }
@@ -155,7 +158,7 @@
                         DFBuffer *output, DFStorage *storage, DFError **error)
 {
     int ok = 0;
-    DFHashTable *includeTypes = DFHashTableNew((DFCopyFunction)strdup,free);
+    DFHashTable *includeTypes = DFHashTableNew((DFCopyFunction)xstrdup,free);
     DFHashTableAdd(includeTypes,WORDREL_HYPERLINK,"");
     DFHashTableAdd(includeTypes,WORDREL_IMAGE,"");
 
@@ -222,7 +225,7 @@
                 if (!DFStringHasSuffix(filename,"/"))
                     absFilename = DFFormatString("/%s",filename);
                 else
-                    absFilename = strdup(filename);
+                    absFilename = xstrdup(filename);
                 DFBuffer *data = DFBufferReadFromStorage(storage,absFilename,NULL);
                 addSerializedBinary(output,data,absFilename);
                 DFBufferRelease(data);
@@ -243,7 +246,7 @@
 static char *Word_toPlainFromDir(DFStorage *storage, DFHashTable *parts, DFError **error)
 {
     char *documentPath = NULL;
-    DFHashTable *rels = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    DFHashTable *rels = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
     DFBuffer *output = DFBufferNew();
     char *relsPathRel = NULL;
     DFDocument *relsDoc = NULL;
@@ -279,7 +282,7 @@
         return NULL;
     }
     else {
-        char *result = strdup(output->data);
+        char *result = xstrdup(output->data);
         DFBufferRelease(output);
         return result;
     }
@@ -421,11 +424,11 @@
 
     const char *documentStr = DFHashTableLookup(tp->items,"document.xml");
     const char **allFilenames = NULL;
-    DFHashTable *ctDefaults = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
-    DFHashTable *ctOverrides = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
-    DFHashTable *docRelURIs = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
-    DFHashTable *docRelTypes = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
-    DFHashTable *docRelModes = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    DFHashTable *ctDefaults = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
+    DFHashTable *ctOverrides = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
+    DFHashTable *docRelURIs = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
+    DFHashTable *docRelTypes = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
+    DFHashTable *docRelModes = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
 
 
     if (documentStr == NULL) {
@@ -516,9 +519,9 @@
         DFHashTableRelease(docRelURIs);
         DFHashTableRelease(docRelTypes);
         DFHashTableRelease(docRelModes);
-        docRelURIs = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
-        docRelTypes = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
-        docRelModes = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+        docRelURIs = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
+        docRelTypes = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
+        docRelModes = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
 
         for (DFNode *child = doc->root->first; child != NULL; child = child->next) {
             if (child->tag == REL_RELATIONSHIP) {
diff --git a/DocFormats/filters/ooxml/tests/word/WordPlain.h b/DocFormats/filters/ooxml/tests/word/WordPlain.h
index 8b44911..93bafb9 100644
--- a/DocFormats/filters/ooxml/tests/word/WordPlain.h
+++ b/DocFormats/filters/ooxml/tests/word/WordPlain.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_WordPlain_h
 #define DocFormats_WordPlain_h
diff --git a/DocFormats/filters/ooxml/tests/word/WordTests.c b/DocFormats/filters/ooxml/tests/word/WordTests.c
index 270403d..e32aef8 100644
--- a/DocFormats/filters/ooxml/tests/word/WordTests.c
+++ b/DocFormats/filters/ooxml/tests/word/WordTests.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFUnitTest.h"
@@ -19,6 +22,7 @@
 #include "Word.h"
 #include "HTMLPlain.h"
 #include "DFString.h"
+#include "DFHTML.h"
 #include <DocFormats/Operations.h>
 #include <stddef.h>
 #include <string.h>
@@ -41,7 +45,7 @@
         return;
     }
 
-    DFHashTable *parts = DFHashTableNew((DFCopyFunction)strdup,free);
+    DFHashTable *parts = DFHashTableNew((DFCopyFunction)xstrdup,free);
     DFHashTableAdd(parts,"document","");
 
     // Output the docx file
@@ -69,7 +73,7 @@
         return;
     }
 
-    DFHashTable *parts = DFHashTableNew((DFCopyFunction)strdup,free);
+    DFHashTable *parts = DFHashTableNew((DFCopyFunction)xstrdup,free);
     DFHashTableAdd(parts,"document","");
 
     // Output the docx file
@@ -95,6 +99,7 @@
 
     concreteDoc = DFConcreteDocumentNew(concreteStorage);
     abstractStorage = DFStorageNewMemory(DFFileFormatHTML);
+    DFStorageWrite(abstractStorage,"test-mode",NULL,0,NULL);
     abstractDoc = DFAbstractDocumentNew(abstractStorage);
 
     if (!DFGet(concreteDoc,abstractDoc,&error))
@@ -106,6 +111,7 @@
         goto end;
     }
 
+    HTMLMetaRemove(htmlDoc,"corinthia-document-hash");
     htmlPlain = HTML_toPlain(htmlDoc,abstractStorage,&error);
 
 end:
@@ -126,7 +132,7 @@
 {
     if (utgetargc() == 0)
         return NULL;;
-    DFHashTable *set = DFHashTableNew((DFCopyFunction)strdup,free);
+    DFHashTable *set = DFHashTableNew((DFCopyFunction)xstrdup,free);
     for (int i = 0; i < utgetargc(); i++) {
         const char *colon = strchr(utgetargv()[i],':');
         if (colon == NULL)
@@ -211,6 +217,7 @@
     if (htmlDoc == NULL)
         goto end;
 
+    HTMLMetaSet(htmlDoc,"corinthia-document-hash","ignore");
     DFAbstractDocumentSetHTML(abstractDoc,htmlDoc);
 
     // Update the docx file based on the contents of the HTML file
diff --git a/DocFormats/headers/DFCommon.h b/DocFormats/headers/DFCommon.h
index 27b3e5c..e9e8f10 100644
--- a/DocFormats/headers/DFCommon.h
+++ b/DocFormats/headers/DFCommon.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFCommon_h
 #define DocFormats_DFCommon_h
diff --git a/DocFormats/headers/DFCore.h b/DocFormats/headers/DFCore.h
index 3505038..8355bd3 100644
--- a/DocFormats/headers/DFCore.h
+++ b/DocFormats/headers/DFCore.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFCore_h
 #define DocFormats_DFCore_h
diff --git a/DocFormats/headers/DFPlatform.h b/DocFormats/headers/DFPlatform.h
index ea517e7..70e4591 100755
--- a/DocFormats/headers/DFPlatform.h
+++ b/DocFormats/headers/DFPlatform.h
@@ -1,21 +1,24 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFPlatform_h
 #define DocFormats_DFPlatform_h
 
-#ifdef WIN32
+#ifdef _WINDOWS
 #include <direct.h>
 
 #define _CRT_SECURE_NO_WARNINGS
@@ -27,12 +30,11 @@
 
 #ifndef snprintf
 #define snprintf _snprintf
-#endif
+#endif // snprintf
 
 #else
 #include <unistd.h>
-#endif
-
+#endif // _WINDOWS
 
 #ifndef ATTRIBUTE_FORMAT
 #ifdef _MSC_VER
@@ -41,10 +43,8 @@
 #else
 #define ATTRIBUTE_FORMAT(archetype,index,first) __attribute__((format(archetype,index,first)))
 #define ATTRIBUTE_ALIGNED(n) __attribute__((aligned (n)))
-#endif
-#endif
-
-
+#endif // _MSC_VER
+#endif // ATTRIBUTE_FORMAT
 
 typedef struct DFDirEntryList DFDirEntryList;
 
@@ -54,13 +54,19 @@
 };
 
 int DFMkdirIfAbsent(const char *path, char **errmsg);
-int DFAddDirContents(const char *absPath, const char *relPath, int recursive, DFDirEntryList ***list, char **errmsg);
-int DFGetImageDimensions(const void *data, size_t len, const char *ext,
-                         unsigned int *width, unsigned int *height, char **errmsg);
+
+int DFAddDirContents(const char *absPath, const char *relPath, 
+                     int recursive, DFDirEntryList ***list, 
+                     char **errmsg);
+
+int DFGetImageDimensions(const void *data, size_t len, 
+                         const char *ext, unsigned int *width, 
+                         unsigned int *height, char **errmsg);
 
 #define DF_ONCE_INIT 0
 typedef int DFOnce;
 typedef void (*DFOnceFunction)(void);
+
 void DFInitOnce(DFOnce *once, DFOnceFunction fun);
 
 // Zip functions
@@ -69,15 +75,36 @@
         int   zipFlag;
         int   zipFirst;
         } DFextZipHandle;
+
 typedef DFextZipHandle * DFextZipHandleP;
 
 DFextZipHandleP DFextZipOpen(const char *zipFilename, int doUnzip);
-int             DFextZipClose(DFextZipHandleP zipHandle);
 
-int             DFextZipOpenNextFile(DFextZipHandleP zipHandle, char *entryName, const int maxName);
-int             DFextZipAppendNewFile(DFextZipHandleP zipHandle, const char *entryName);
-int             DFextZipCloseFile(DFextZipHandleP zipHandle);
+int DFextZipClose(DFextZipHandleP zipHandle);
 
-int DFextZipReadCurrentFile(DFextZipHandleP zipHandle, void *buf, const int maxLen);
-int DFextZipWriteCurrentFile(DFextZipHandleP zipHandle, const void *buf, const int len);
-#endif
+int DFextZipOpenNextFile(DFextZipHandleP zipHandle,
+                         char *entryName,
+                         const int maxName);
+
+int DFextZipAppendNewFile(DFextZipHandleP zipHandle,
+                          const char *entryName);
+
+int DFextZipCloseFile(DFextZipHandleP zipHandle);
+
+int DFextZipReadCurrentFile(DFextZipHandleP zipHandle,
+                            void *buf,
+                            const int maxLen);
+
+int DFextZipWriteCurrentFile(DFextZipHandleP zipHandle,
+                             const void *buf,
+                             const int len);
+
+void *xmalloc(size_t size);
+
+void *xcalloc(size_t nmemb, size_t size);
+
+void *xrealloc(void *ptr, size_t size);
+
+char *xstrdup(const char *s);
+
+#endif // DocFormats_DFPlatform_h
diff --git a/DocFormats/headers/DFTypes.h b/DocFormats/headers/DFTypes.h
index 3b563c0..ef63766 100644
--- a/DocFormats/headers/DFTypes.h
+++ b/DocFormats/headers/DFTypes.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFTypes_h
 #define DocFormats_DFTypes_h
diff --git a/DocFormats/platform/src/Apple.c b/DocFormats/platform/src/Apple.c
index 3c9d130..576743f 100644
--- a/DocFormats/platform/src/Apple.c
+++ b/DocFormats/platform/src/Apple.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 
diff --git a/DocFormats/platform/src/Linux.c b/DocFormats/platform/src/Linux.c
index 5d93518..bba6658 100644
--- a/DocFormats/platform/src/Linux.c
+++ b/DocFormats/platform/src/Linux.c
@@ -1,22 +1,25 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 
 // This file contains functions that are applicable to Linux (or more generally, any non-Apple Unix platform)
 
-#ifndef WIN32
+#ifndef _WINDOWS
 #ifndef __APPLE__
 
 #include <SDL2/SDL_image.h>
@@ -27,7 +30,7 @@
     SDL_Surface *image = IMG_Load_RW(SDL_RWFromMem((void *)data,len),1);
     if (image == NULL) {
         if (errmsg != NULL)
-            *errmsg = strdup(IMG_GetError());
+            *errmsg = xstrdup(IMG_GetError());
         return 0;
     }
 
diff --git a/DocFormats/platform/src/Unix.c b/DocFormats/platform/src/Unix.c
index 00c8438..c318548 100644
--- a/DocFormats/platform/src/Unix.c
+++ b/DocFormats/platform/src/Unix.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include <errno.h>
@@ -21,7 +24,7 @@
 
 // This file contains functions that are applicable to all Unix-based platforms, including Linux, iOS, and OS X
 
-#ifndef WIN32
+#ifndef _WINDOWS
 
 #include <pthread.h>
 #include <dirent.h>
@@ -47,7 +50,7 @@
     if ((mkdir(path,0777) != 0) && (errno != EEXIST)) {
         printf("DFMkdirIfAbsent: errno = %d (%s)\n",errno,strerror(errno));
         if (errmsg != NULL)
-            *errmsg = strdup(strerror(errno));
+            *errmsg = xstrdup(strerror(errno));
         return 0;
     }
     return 1;
@@ -62,7 +65,7 @@
         if (errmsg != NULL) {
             char temp[1024];
             snprintf(temp,1024,"%s: %s",relPath,strerror(errno));
-            *errmsg = strdup(temp);
+            *errmsg = xstrdup(temp);
         }
         return 0;
     }
@@ -77,8 +80,8 @@
         size_t absSubPathLen = strlen(absPath) + 1 + strlen(result->d_name);
         size_t relSubPathLen = strlen(relPath) + 1 + strlen(result->d_name);
 
-        char *absSubPath = (char *)malloc(absSubPathLen+1);
-        char *relSubPath = (char *)malloc(relSubPathLen+1);
+        char *absSubPath = (char *)xmalloc(absSubPathLen+1);
+        char *relSubPath = (char *)xmalloc(relSubPathLen+1);
 
         snprintf(absSubPath,absSubPathLen+1,"%s/%s",absPath,result->d_name);
         snprintf(relSubPath,relSubPathLen+1,"%s/%s",relPath,result->d_name);
@@ -89,8 +92,8 @@
         else
             entryName = relSubPath;
 
-        *listptr = (DFDirEntryList *)calloc(1,sizeof(DFDirEntryList));
-        (*listptr)->name = strdup(entryName);
+        *listptr = (DFDirEntryList *)xcalloc(1,sizeof(DFDirEntryList));
+        (*listptr)->name = xstrdup(entryName);
         listptr = &(*listptr)->next;
 
         struct stat statbuf;
diff --git a/DocFormats/platform/src/Win32.c b/DocFormats/platform/src/Win32.c
index f17303e..43cdbb2 100755
--- a/DocFormats/platform/src/Win32.c
+++ b/DocFormats/platform/src/Win32.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 
@@ -44,7 +47,7 @@
             (lpMsgBuf[len - 1] == '.')))
         len--;
     lpMsgBuf[len] = '\0';
-    *errmsg = strdup(lpMsgBuf);
+    *errmsg = xstrdup(lpMsgBuf);
     LocalFree(lpMsgBuf);
 }
 
@@ -89,7 +92,7 @@
     HANDLE hFind = INVALID_HANDLE_VALUE;
 
     size_t patternLen = strlen(absPath) + 2;
-    char *pattern = (char *)malloc(patternLen+1);
+    char *pattern = (char *)xmalloc(patternLen+1);
     snprintf(pattern,patternLen+1,"%s/*",absPath);
     hFind = FindFirstFile(pattern,&ffd);
     if (hFind == INVALID_HANDLE_VALUE) {
@@ -106,8 +109,8 @@
         size_t absSubPathLen = strlen(absPath) + 1 + strlen(ffd.cFileName);
         size_t relSubPathLen = strlen(relPath) + 1 + strlen(ffd.cFileName);
 
-        char *absSubPath = (char *)malloc(absSubPathLen+1);
-        char *relSubPath = (char *)malloc(relSubPathLen+1);
+        char *absSubPath = (char *)xmalloc(absSubPathLen+1);
+        char *relSubPath = (char *)xmalloc(relSubPathLen+1);
 
         snprintf(absSubPath,absSubPathLen+1,"%s/%s",absPath,ffd.cFileName);
         snprintf(relSubPath,relSubPathLen+1,"%s/%s",relPath,ffd.cFileName);
@@ -118,8 +121,8 @@
         else
             entryName = relSubPath;
 
-        *listptr = (DFDirEntryList *)calloc(1,sizeof(DFDirEntryList));
-        (*listptr)->name = strdup(entryName);
+        *listptr = (DFDirEntryList *)xcalloc(1,sizeof(DFDirEntryList));
+        (*listptr)->name = xstrdup(entryName);
         listptr = &(*listptr)->next;
 
         if (recursive && (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
@@ -141,7 +144,7 @@
     SDL_Surface *image = IMG_Load_RW(SDL_RWFromMem((void *)data,len),1);
     if (image == NULL) {
         if (errmsg != NULL)
-            *errmsg = strdup(IMG_GetError());
+            *errmsg = xstrdup(IMG_GetError());
         return 0;
     }
 
diff --git a/DocFormats/platform/src/Wrapper.c b/DocFormats/platform/src/Wrapper.c
index 14ed093..1e8e506 100644
--- a/DocFormats/platform/src/Wrapper.c
+++ b/DocFormats/platform/src/Wrapper.c
@@ -1,25 +1,30 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
+
 #include <string.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include "DFPlatform.h"
 #include "unzip.h"
 #include "zip.h"
 
 
 DFextZipHandleP DFextZipOpen(const char *zipFilename, int doUnzip) {
-    DFextZipHandleP zipHandle = malloc(sizeof(DFextZipHandle));
+    DFextZipHandleP zipHandle = xmalloc(sizeof(DFextZipHandle));
  
     // no more memory
     if (!zipHandle)
@@ -144,3 +149,55 @@
 {
     return (zipWriteInFileInZip(zipHandle->handle, buf, len) == ZIP_OK) ? 1 : -1;
 }
+
+
+
+void *xmalloc(size_t size)
+{
+    void *ptr = malloc(size);
+
+    if (ptr == NULL) {
+        perror("xmalloc: out of memory.\n");
+        abort();
+        return NULL;
+    }
+
+    return ptr;
+}
+
+
+
+void *xcalloc(size_t nmemb, size_t size)
+{
+    void *ptr = calloc(nmemb, size);
+
+    if (ptr == NULL) {
+        perror("xcalloc: out of memory.\n");
+        abort();
+        return NULL;
+    }
+
+    return ptr;
+}
+
+
+
+void *xrealloc(void *in_ptr, size_t size)
+{
+    void *ptr = realloc(in_ptr, size);
+
+    if (ptr == NULL) {
+        perror("xrealloc: out of memory.\n");
+        abort();
+        return NULL;
+    }
+
+    return ptr;
+}
+
+
+char *xstrdup(const char *s)
+{
+    size_t l = strlen(s)+1;
+    return (char*) memcpy (xmalloc (l), s, l);
+}
diff --git a/DocFormats/platform/tests/OStests.c b/DocFormats/platform/tests/OStests.c
index a1f430a..6ee74f1 100644
--- a/DocFormats/platform/tests/OStests.c
+++ b/DocFormats/platform/tests/OStests.c
@@ -1,21 +1,24 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFUnitTest.h"
 #include "DFPlatform.h"
 #include <stddef.h>
-
+#include <stdlib.h>
 
 static void test_DFGetImageDimensions_gif(void)
 {
@@ -172,11 +175,16 @@
     char            *errmsg;
     int              rc;
 
-
     rc = DFAddDirContents(".", "", 1, &listptr, &errmsg);
     utassert((rc == 1), "could not read dir");
-}
 
+    DFDirEntryList *next;
+    for (DFDirEntryList *l = list; l != NULL; l = next) {
+        next = l->next;
+        free(l->name);
+        free(l);
+    }
+}
 
 
 TestGroup PlatformOSTests = {
diff --git a/DocFormats/platform/tests/WrapperTests.c b/DocFormats/platform/tests/WrapperTests.c
index f2a8f2b..5f5d74b 100644
--- a/DocFormats/platform/tests/WrapperTests.c
+++ b/DocFormats/platform/tests/WrapperTests.c
@@ -1,16 +1,20 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
+
 #include "DFUnitTest.h"
 #include <stddef.h>
 
diff --git a/DocFormats/unittest/DFUnitTest.c b/DocFormats/unittest/DFUnitTest.c
index 65a47d9..17e8ae1 100644
--- a/DocFormats/unittest/DFUnitTest.c
+++ b/DocFormats/unittest/DFUnitTest.c
@@ -1,18 +1,22 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFUnitTest.h"
+#include "DFPlatform.h"
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -59,7 +63,7 @@
 {
     if (!condition) {
         curtest.failed = 1;
-        curtest.reason = strdup(description);
+        curtest.reason = xstrdup(description);
     }
 }
 
@@ -67,14 +71,14 @@
 {
     if (strcmp(actual,expected)) {
         curtest.failed = 1;
-        curtest.reason = strdup("Output mismatch");
+        curtest.reason = xstrdup("Output mismatch");
     }
 }
 
 void utfail(const char *reason)
 {
     curtest.failed = 1;
-    curtest.reason = strdup(reason);
+    curtest.reason = xstrdup(reason);
 }
 
 TestCase *utlookup(TestGroup **groups, const char *name)
diff --git a/DocFormats/unittest/DFUnitTest.h b/DocFormats/unittest/DFUnitTest.h
index 08b1729..1a24d46 100644
--- a/DocFormats/unittest/DFUnitTest.h
+++ b/DocFormats/unittest/DFUnitTest.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef DocFormats_DFUnitTest_h
 #define DocFormats_DFUnitTest_h
diff --git a/Editor/src/3rdparty/showdown/license.txt b/Editor/src/3rdparty/showdown/license.txt
index a6096c8..e9c8672 100644
--- a/Editor/src/3rdparty/showdown/license.txt
+++ b/Editor/src/3rdparty/showdown/license.txt
@@ -1,34 +1,34 @@
-Copyright (c) 2007, John Fraser  

-<http://www.attacklab.net/>  

-All rights reserved.

-

-Original Markdown copyright (c) 2004, John Gruber  

-<http://daringfireball.net/>  

-All rights reserved.

-

-Redistribution and use in source and binary forms, with or without

-modification, are permitted provided that the following conditions are

-met:

-

-* Redistributions of source code must retain the above copyright notice,

-  this list of conditions and the following disclaimer.

-

-* Redistributions in binary form must reproduce the above copyright

-  notice, this list of conditions and the following disclaimer in the

-  documentation and/or other materials provided with the distribution.

-

-* Neither the name "Markdown" nor the names of its contributors may

-  be used to endorse or promote products derived from this software

-  without specific prior written permission.

-

-This software is provided by the copyright holders and contributors "as

-is" and any express or implied warranties, including, but not limited

-to, the implied warranties of merchantability and fitness for a

-particular purpose are disclaimed. In no event shall the copyright owner

-or contributors be liable for any direct, indirect, incidental, special,

-exemplary, or consequential damages (including, but not limited to,

-procurement of substitute goods or services; loss of use, data, or

-profits; or business interruption) however caused and on any theory of

-liability, whether in contract, strict liability, or tort (including

-negligence or otherwise) arising in any way out of the use of this

-software, even if advised of the possibility of such damage.

+Copyright (c) 2007, John Fraser  
+<http://www.attacklab.net/>  
+All rights reserved.
+
+Original Markdown copyright (c) 2004, John Gruber  
+<http://daringfireball.net/>  
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name "Markdown" nor the names of its contributors may
+  be used to endorse or promote products derived from this software
+  without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as
+is" and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed. In no event shall the copyright owner
+or contributors be liable for any direct, indirect, incidental, special,
+exemplary, or consequential damages (including, but not limited to,
+procurement of substitute goods or services; loss of use, data, or
+profits; or business interruption) however caused and on any theory of
+liability, whether in contract, strict liability, or tort (including
+negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
diff --git a/Editor/src/3rdparty/showdown/showdown.js b/Editor/src/3rdparty/showdown/showdown.js
index c38bf0c..734dabb 100644
--- a/Editor/src/3rdparty/showdown/showdown.js
+++ b/Editor/src/3rdparty/showdown/showdown.js
@@ -1,1302 +1,1302 @@
-//

-// showdown.js -- A javascript port of Markdown.

-//

-// Copyright (c) 2007 John Fraser.

-//

-// Original Markdown Copyright (c) 2004-2005 John Gruber

-//   <http://daringfireball.net/projects/markdown/>

-//

-// Redistributable under a BSD-style open source license.

-// See license.txt for more information.

-//

-// The full source distribution is at:

-//

-//				A A L

-//				T C A

-//				T K B

-//

-//   <http://www.attacklab.net/>

-//

-

-//

-// Wherever possible, Showdown is a straight, line-by-line port

-// of the Perl version of Markdown.

-//

-// This is not a normal parser design; it's basically just a

-// series of string substitutions.  It's hard to read and

-// maintain this way,  but keeping Showdown close to the original

-// design makes it easier to port new features.

-//

-// More importantly, Showdown behaves like markdown.pl in most

-// edge cases.  So web applications can do client-side preview

-// in Javascript, and then build identical HTML on the server.

-//

-// This port needs the new RegExp functionality of ECMA 262,

-// 3rd Edition (i.e. Javascript 1.5).  Most modern web browsers

-// should do fine.  Even with the new regular expression features,

-// We do a lot of work to emulate Perl's regex functionality.

-// The tricky changes in this file mostly have the "attacklab:"

-// label.  Major or self-explanatory changes don't.

-//

-// Smart diff tools like Araxis Merge will be able to match up

-// this file with markdown.pl in a useful way.  A little tweaking

-// helps: in a copy of markdown.pl, replace "#" with "//" and

-// replace "$text" with "text".  Be sure to ignore whitespace

-// and line endings.

-//

-

-

-//

-// Showdown usage:

-//

-//   var text = "Markdown *rocks*.";

-//

-//   var converter = new Showdown.converter();

-//   var html = converter.makeHtml(text);

-//

-//   alert(html);

-//

-// Note: move the sample code to the bottom of this

-// file before uncommenting it.

-//

-

-

-//

-// Showdown namespace

-//

-var Showdown = {};

-

-//

-// converter

-//

-// Wraps all "globals" so that the only thing

-// exposed is makeHtml().

-//

-Showdown.converter = function() {

-

-//

-// Globals:

-//

-

-// Global hashes, used by various utility routines

-var g_urls;

-var g_titles;

-var g_html_blocks;

-

-// Used to track when we're inside an ordered or unordered list

-// (see _ProcessListItems() for details):

-var g_list_level = 0;

-

-

-this.makeHtml = function(text) {

-//

-// Main function. The order in which other subs are called here is

-// essential. Link and image substitutions need to happen before

-// _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the <a>

-// and <img> tags get encoded.

-//

-

-	// Clear the global hashes. If we don't clear these, you get conflicts

-	// from other articles when generating a page which contains more than

-	// one article (e.g. an index page that shows the N most recent

-	// articles):

-	g_urls = new Array();

-	g_titles = new Array();

-	g_html_blocks = new Array();

-

-	// attacklab: Replace ~ with ~T

-	// This lets us use tilde as an escape char to avoid md5 hashes

-	// The choice of character is arbitray; anything that isn't

-    // magic in Markdown will work.

-	text = text.replace(/~/g,"~T");

-

-	// attacklab: Replace $ with ~D

-	// RegExp interprets $ as a special character

-	// when it's in a replacement string

-	text = text.replace(/\$/g,"~D");

-

-	// Standardize line endings

-	text = text.replace(/\r\n/g,"\n"); // DOS to Unix

-	text = text.replace(/\r/g,"\n"); // Mac to Unix

-

-	// Make sure text begins and ends with a couple of newlines:

-	text = "\n\n" + text + "\n\n";

-

-	// Convert all tabs to spaces.

-	text = _Detab(text);

-

-	// Strip any lines consisting only of spaces and tabs.

-	// This makes subsequent regexen easier to write, because we can

-	// match consecutive blank lines with /\n+/ instead of something

-	// contorted like /[ \t]*\n+/ .

-	text = text.replace(/^[ \t]+$/mg,"");

-

-	// Turn block-level HTML blocks into hash entries

-	text = _HashHTMLBlocks(text);

-

-	// Strip link definitions, store in hashes.

-	text = _StripLinkDefinitions(text);

-

-	text = _RunBlockGamut(text);

-

-	text = _UnescapeSpecialChars(text);

-

-	// attacklab: Restore dollar signs

-	text = text.replace(/~D/g,"$$");

-

-	// attacklab: Restore tildes

-	text = text.replace(/~T/g,"~");

-

-	return text;

-}

-

-

-var _StripLinkDefinitions = function(text) {

-//

-// Strips link definitions from text, stores the URLs and titles in

-// hash references.

-//

-

-	// Link defs are in the form: ^[id]: url "optional title"

-

-	/*

-		var text = text.replace(/

-				^[ ]{0,3}\[(.+)\]:  // id = $1  attacklab: g_tab_width - 1

-				  [ \t]*

-				  \n?				// maybe *one* newline

-				  [ \t]*

-				<?(\S+?)>?			// url = $2

-				  [ \t]*

-				  \n?				// maybe one newline

-				  [ \t]*

-				(?:

-				  (\n*)				// any lines skipped = $3 attacklab: lookbehind removed

-				  ["(]

-				  (.+?)				// title = $4

-				  [")]

-				  [ \t]*

-				)?					// title is optional

-				(?:\n+|$)

-			  /gm,

-			  function(){...});

-	*/

-	var text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|\Z)/gm,

-		function (wholeMatch,m1,m2,m3,m4) {

-			m1 = m1.toLowerCase();

-			g_urls[m1] = _EncodeAmpsAndAngles(m2);  // Link IDs are case-insensitive

-			if (m3) {

-				// Oops, found blank lines, so it's not a title.

-				// Put back the parenthetical statement we stole.

-				return m3+m4;

-			} else if (m4) {

-				g_titles[m1] = m4.replace(/"/g,"&quot;");

-			}

-			

-			// Completely remove the definition from the text

-			return "";

-		}

-	);

-

-	return text;

-}

-

-

-var _HashHTMLBlocks = function(text) {

-	// attacklab: Double up blank lines to reduce lookaround

-	text = text.replace(/\n/g,"\n\n");

-

-	// Hashify HTML blocks:

-	// We only want to do this for block-level HTML tags, such as headers,

-	// lists, and tables. That's because we still want to wrap <p>s around

-	// "paragraphs" that are wrapped in non-block-level tags, such as anchors,

-	// phrase emphasis, and spans. The list of tags we're looking for is

-	// hard-coded:

-	var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"

-	var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math"

-

-	// First, look for nested blocks, e.g.:

-	//   <div>

-	//     <div>

-	//     tags for inner block must be indented.

-	//     </div>

-	//   </div>

-	//

-	// The outermost tags must start at the left margin for this to match, and

-	// the inner nested divs must be indented.

-	// We need to do this before the next, more liberal match, because the next

-	// match will start at the first `<div>` and stop at the first `</div>`.

-

-	// attacklab: This regex can be expensive when it fails.

-	/*

-		var text = text.replace(/

-		(						// save in $1

-			^					// start of line  (with /m)

-			<($block_tags_a)	// start tag = $2

-			\b					// word break

-								// attacklab: hack around khtml/pcre bug...

-			[^\r]*?\n			// any number of lines, minimally matching

-			</\2>				// the matching end tag

-			[ \t]*				// trailing spaces/tabs

-			(?=\n+)				// followed by a newline

-		)						// attacklab: there are sentinel newlines at end of document

-		/gm,function(){...}};

-	*/

-	text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,hashElement);

-

-	//

-	// Now match more liberally, simply from `\n<tag>` to `</tag>\n`

-	//

-

-	/*

-		var text = text.replace(/

-		(						// save in $1

-			^					// start of line  (with /m)

-			<($block_tags_b)	// start tag = $2

-			\b					// word break

-								// attacklab: hack around khtml/pcre bug...

-			[^\r]*?				// any number of lines, minimally matching

-			.*</\2>				// the matching end tag

-			[ \t]*				// trailing spaces/tabs

-			(?=\n+)				// followed by a newline

-		)						// attacklab: there are sentinel newlines at end of document

-		/gm,function(){...}};

-	*/

-	text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm,hashElement);

-

-	// Special case just for <hr />. It was easier to make a special case than

-	// to make the other regex more complicated.  

-

-	/*

-		text = text.replace(/

-		(						// save in $1

-			\n\n				// Starting after a blank line

-			[ ]{0,3}

-			(<(hr)				// start tag = $2

-			\b					// word break

-			([^<>])*?			// 

-			\/?>)				// the matching end tag

-			[ \t]*

-			(?=\n{2,})			// followed by a blank line

-		)

-		/g,hashElement);

-	*/

-	text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,hashElement);

-

-	// Special case for standalone HTML comments:

-

-	/*

-		text = text.replace(/

-		(						// save in $1

-			\n\n				// Starting after a blank line

-			[ ]{0,3}			// attacklab: g_tab_width - 1

-			<!

-			(--[^\r]*?--\s*)+

-			>

-			[ \t]*

-			(?=\n{2,})			// followed by a blank line

-		)

-		/g,hashElement);

-	*/

-	text = text.replace(/(\n\n[ ]{0,3}<!(--[^\r]*?--\s*)+>[ \t]*(?=\n{2,}))/g,hashElement);

-

-	// PHP and ASP-style processor instructions (<?...?> and <%...%>)

-

-	/*

-		text = text.replace(/

-		(?:

-			\n\n				// Starting after a blank line

-		)

-		(						// save in $1

-			[ ]{0,3}			// attacklab: g_tab_width - 1

-			(?:

-				<([?%])			// $2

-				[^\r]*?

-				\2>

-			)

-			[ \t]*

-			(?=\n{2,})			// followed by a blank line

-		)

-		/g,hashElement);

-	*/

-	text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,hashElement);

-

-	// attacklab: Undo double lines (see comment at top of this function)

-	text = text.replace(/\n\n/g,"\n");

-	return text;

-}

-

-var hashElement = function(wholeMatch,m1) {

-	var blockText = m1;

-

-	// Undo double lines

-	blockText = blockText.replace(/\n\n/g,"\n");

-	blockText = blockText.replace(/^\n/,"");

-	

-	// strip trailing blank lines

-	blockText = blockText.replace(/\n+$/g,"");

-	

-	// Replace the element text with a marker ("~KxK" where x is its key)

-	blockText = "\n\n~K" + (g_html_blocks.push(blockText)-1) + "K\n\n";

-	

-	return blockText;

-};

-

-var _RunBlockGamut = function(text) {

-//

-// These are all the transformations that form block-level

-// tags like paragraphs, headers, and list items.

-//

-	text = _DoHeaders(text);

-

-	// Do Horizontal Rules:

-	var key = hashBlock("<hr />");

-	text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,key);

-	text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,key);

-	text = text.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,key);

-

-	text = _DoLists(text);

-	text = _DoCodeBlocks(text);

-	text = _DoBlockQuotes(text);

-

-	// We already ran _HashHTMLBlocks() before, in Markdown(), but that

-	// was to escape raw HTML in the original Markdown source. This time,

-	// we're escaping the markup we've just created, so that we don't wrap

-	// <p> tags around block-level tags.

-	text = _HashHTMLBlocks(text);

-	text = _FormParagraphs(text);

-

-	return text;

-}

-

-

-var _RunSpanGamut = function(text) {

-//

-// These are all the transformations that occur *within* block-level

-// tags like paragraphs, headers, and list items.

-//

-

-	text = _DoCodeSpans(text);

-	text = _EscapeSpecialCharsWithinTagAttributes(text);

-	text = _EncodeBackslashEscapes(text);

-

-	// Process anchor and image tags. Images must come first,

-	// because ![foo][f] looks like an anchor.

-	text = _DoImages(text);

-	text = _DoAnchors(text);

-

-	// Make links out of things like `<http://example.com/>`

-	// Must come after _DoAnchors(), because you can use < and >

-	// delimiters in inline links like [this](<url>).

-	text = _DoAutoLinks(text);

-	text = _EncodeAmpsAndAngles(text);

-	text = _DoItalicsAndBold(text);

-

-	// Do hard breaks:

-	text = text.replace(/  +\n/g," <br />\n");

-

-	return text;

-}

-

-var _EscapeSpecialCharsWithinTagAttributes = function(text) {

-//

-// Within tags -- meaning between < and > -- encode [\ ` * _] so they

-// don't conflict with their use in Markdown for code, italics and strong.

-//

-

-	// Build a regex to find HTML tags and comments.  See Friedl's 

-	// "Mastering Regular Expressions", 2nd Ed., pp. 200-201.

-	var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;

-

-	text = text.replace(regex, function(wholeMatch) {

-		var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`");

-		tag = escapeCharacters(tag,"\\`*_");

-		return tag;

-	});

-

-	return text;

-}

-

-var _DoAnchors = function(text) {

-//

-// Turn Markdown link shortcuts into XHTML <a> tags.

-//

-	//

-	// First, handle reference-style links: [link text] [id]

-	//

-

-	/*

-		text = text.replace(/

-		(							// wrap whole match in $1

-			\[

-			(

-				(?:

-					\[[^\]]*\]		// allow brackets nested one level

-					|

-					[^\[]			// or anything else

-				)*

-			)

-			\]

-

-			[ ]?					// one optional space

-			(?:\n[ ]*)?				// one optional newline followed by spaces

-

-			\[

-			(.*?)					// id = $3

-			\]

-		)()()()()					// pad remaining backreferences

-		/g,_DoAnchors_callback);

-	*/

-	text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag);

-

-	//

-	// Next, inline-style links: [link text](url "optional title")

-	//

-

-	/*

-		text = text.replace(/

-			(						// wrap whole match in $1

-				\[

-				(

-					(?:

-						\[[^\]]*\]	// allow brackets nested one level

-					|

-					[^\[\]]			// or anything else

-				)

-			)

-			\]

-			\(						// literal paren

-			[ \t]*

-			()						// no id, so leave $3 empty

-			<?(.*?)>?				// href = $4

-			[ \t]*

-			(						// $5

-				(['"])				// quote char = $6

-				(.*?)				// Title = $7

-				\6					// matching quote

-				[ \t]*				// ignore any spaces/tabs between closing quote and )

-			)?						// title is optional

-			\)

-		)

-		/g,writeAnchorTag);

-	*/

-	text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag);

-

-	//

-	// Last, handle reference-style shortcuts: [link text]

-	// These must come last in case you've also got [link test][1]

-	// or [link test](/foo)

-	//

-

-	/*

-		text = text.replace(/

-		(		 					// wrap whole match in $1

-			\[

-			([^\[\]]+)				// link text = $2; can't contain '[' or ']'

-			\]

-		)()()()()()					// pad rest of backreferences

-		/g, writeAnchorTag);

-	*/

-	text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);

-

-	return text;

-}

-

-var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {

-	if (m7 == undefined) m7 = "";

-	var whole_match = m1;

-	var link_text   = m2;

-	var link_id	 = m3.toLowerCase();

-	var url		= m4;

-	var title	= m7;

-	

-	if (url == "") {

-		if (link_id == "") {

-			// lower-case and turn embedded newlines into spaces

-			link_id = link_text.toLowerCase().replace(/ ?\n/g," ");

-		}

-		url = "#"+link_id;

-		

-		if (g_urls[link_id] != undefined) {

-			url = g_urls[link_id];

-			if (g_titles[link_id] != undefined) {

-				title = g_titles[link_id];

-			}

-		}

-		else {

-			if (whole_match.search(/\(\s*\)$/m)>-1) {

-				// Special case for explicit empty url

-				url = "";

-			} else {

-				return whole_match;

-			}

-		}

-	}	

-	

-	url = escapeCharacters(url,"*_");

-	var result = "<a href=\"" + url + "\"";

-	

-	if (title != "") {

-		title = title.replace(/"/g,"&quot;");

-		title = escapeCharacters(title,"*_");

-		result +=  " title=\"" + title + "\"";

-	}

-	

-	result += ">" + link_text + "</a>";

-	

-	return result;

-}

-

-

-var _DoImages = function(text) {

-//

-// Turn Markdown image shortcuts into <img> tags.

-//

-

-	//

-	// First, handle reference-style labeled images: ![alt text][id]

-	//

-

-	/*

-		text = text.replace(/

-		(						// wrap whole match in $1

-			!\[

-			(.*?)				// alt text = $2

-			\]

-

-			[ ]?				// one optional space

-			(?:\n[ ]*)?			// one optional newline followed by spaces

-

-			\[

-			(.*?)				// id = $3

-			\]

-		)()()()()				// pad rest of backreferences

-		/g,writeImageTag);

-	*/

-	text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag);

-

-	//

-	// Next, handle inline images:  ![alt text](url "optional title")

-	// Don't forget: encode * and _

-

-	/*

-		text = text.replace(/

-		(						// wrap whole match in $1

-			!\[

-			(.*?)				// alt text = $2

-			\]

-			\s?					// One optional whitespace character

-			\(					// literal paren

-			[ \t]*

-			()					// no id, so leave $3 empty

-			<?(\S+?)>?			// src url = $4

-			[ \t]*

-			(					// $5

-				(['"])			// quote char = $6

-				(.*?)			// title = $7

-				\6				// matching quote

-				[ \t]*

-			)?					// title is optional

-		\)

-		)

-		/g,writeImageTag);

-	*/

-	text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag);

-

-	return text;

-}

-

-var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {

-	var whole_match = m1;

-	var alt_text   = m2;

-	var link_id	 = m3.toLowerCase();

-	var url		= m4;

-	var title	= m7;

-

-	if (!title) title = "";

-	

-	if (url == "") {

-		if (link_id == "") {

-			// lower-case and turn embedded newlines into spaces

-			link_id = alt_text.toLowerCase().replace(/ ?\n/g," ");

-		}

-		url = "#"+link_id;

-		

-		if (g_urls[link_id] != undefined) {

-			url = g_urls[link_id];

-			if (g_titles[link_id] != undefined) {

-				title = g_titles[link_id];

-			}

-		}

-		else {

-			return whole_match;

-		}

-	}	

-	

-	alt_text = alt_text.replace(/"/g,"&quot;");

-	url = escapeCharacters(url,"*_");

-	var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\"";

-

-	// attacklab: Markdown.pl adds empty title attributes to images.

-	// Replicate this bug.

-

-	//if (title != "") {

-		title = title.replace(/"/g,"&quot;");

-		title = escapeCharacters(title,"*_");

-		result +=  " title=\"" + title + "\"";

-	//}

-	

-	result += " />";

-	

-	return result;

-}

-

-

-var _DoHeaders = function(text) {

-

-	// Setext-style headers:

-	//	Header 1

-	//	========

-	//  

-	//	Header 2

-	//	--------

-	//

-	text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,

-		function(wholeMatch,m1){return hashBlock('<h1 id="' + headerId(m1) + '">' + _RunSpanGamut(m1) + "</h1>");});

-

-	text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,

-		function(matchFound,m1){return hashBlock('<h2 id="' + headerId(m1) + '">' + _RunSpanGamut(m1) + "</h2>");});

-

-	// atx-style headers:

-	//  # Header 1

-	//  ## Header 2

-	//  ## Header 2 with closing hashes ##

-	//  ...

-	//  ###### Header 6

-	//

-

-	/*

-		text = text.replace(/

-			^(\#{1,6})				// $1 = string of #'s

-			[ \t]*

-			(.+?)					// $2 = Header text

-			[ \t]*

-			\#*						// optional closing #'s (not counted)

-			\n+

-		/gm, function() {...});

-	*/

-

-	text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,

-		function(wholeMatch,m1,m2) {

-			var h_level = m1.length;

-			return hashBlock("<h" + h_level + ' id="' + headerId(m2) + '">' + _RunSpanGamut(m2) + "</h" + h_level + ">");

-		});

-

-	function headerId(m) {

-		return m.replace(/[^\w]/g, '').toLowerCase();

-	}

-	return text;

-}

-

-// This declaration keeps Dojo compressor from outputting garbage:

-var _ProcessListItems;

-

-var _DoLists = function(text) {

-//

-// Form HTML ordered (numbered) and unordered (bulleted) lists.

-//

-

-	// attacklab: add sentinel to hack around khtml/safari bug:

-	// http://bugs.webkit.org/show_bug.cgi?id=11231

-	text += "~0";

-

-	// Re-usable pattern to match any entirel ul or ol list:

-

-	/*

-		var whole_list = /

-		(									// $1 = whole list

-			(								// $2

-				[ ]{0,3}					// attacklab: g_tab_width - 1

-				([*+-]|\d+[.])				// $3 = first list item marker

-				[ \t]+

-			)

-			[^\r]+?

-			(								// $4

-				~0							// sentinel for workaround; should be $

-			|

-				\n{2,}

-				(?=\S)

-				(?!							// Negative lookahead for another list item marker

-					[ \t]*

-					(?:[*+-]|\d+[.])[ \t]+

-				)

-			)

-		)/g

-	*/

-	var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;

-

-	if (g_list_level) {

-		text = text.replace(whole_list,function(wholeMatch,m1,m2) {

-			var list = m1;

-			var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol";

-

-			// Turn double returns into triple returns, so that we can make a

-			// paragraph for the last item in a list, if necessary:

-			list = list.replace(/\n{2,}/g,"\n\n\n");;

-			var result = _ProcessListItems(list);

-	

-			// Trim any trailing whitespace, to put the closing `</$list_type>`

-			// up on the preceding line, to get it past the current stupid

-			// HTML block parser. This is a hack to work around the terrible

-			// hack that is the HTML block parser.

-			result = result.replace(/\s+$/,"");

-			result = "<"+list_type+">" + result + "</"+list_type+">\n";

-			return result;

-		});

-	} else {

-		whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g;

-		text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) {

-			var runup = m1;

-			var list = m2;

-

-			var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol";

-			// Turn double returns into triple returns, so that we can make a

-			// paragraph for the last item in a list, if necessary:

-			var list = list.replace(/\n{2,}/g,"\n\n\n");;

-			var result = _ProcessListItems(list);

-			result = runup + "<"+list_type+">\n" + result + "</"+list_type+">\n";	

-			return result;

-		});

-	}

-

-	// attacklab: strip sentinel

-	text = text.replace(/~0/,"");

-

-	return text;

-}

-

-_ProcessListItems = function(list_str) {

-//

-//  Process the contents of a single ordered or unordered list, splitting it

-//  into individual list items.

-//

-	// The $g_list_level global keeps track of when we're inside a list.

-	// Each time we enter a list, we increment it; when we leave a list,

-	// we decrement. If it's zero, we're not in a list anymore.

-	//

-	// We do this because when we're not inside a list, we want to treat

-	// something like this:

-	//

-	//    I recommend upgrading to version

-	//    8. Oops, now this line is treated

-	//    as a sub-list.

-	//

-	// As a single paragraph, despite the fact that the second line starts

-	// with a digit-period-space sequence.

-	//

-	// Whereas when we're inside a list (or sub-list), that line will be

-	// treated as the start of a sub-list. What a kludge, huh? This is

-	// an aspect of Markdown's syntax that's hard to parse perfectly

-	// without resorting to mind-reading. Perhaps the solution is to

-	// change the syntax rules such that sub-lists must start with a

-	// starting cardinal number; e.g. "1." or "a.".

-

-	g_list_level++;

-

-	// trim trailing blank lines:

-	list_str = list_str.replace(/\n{2,}$/,"\n");

-

-	// attacklab: add sentinel to emulate \z

-	list_str += "~0";

-

-	/*

-		list_str = list_str.replace(/

-			(\n)?							// leading line = $1

-			(^[ \t]*)						// leading whitespace = $2

-			([*+-]|\d+[.]) [ \t]+			// list marker = $3

-			([^\r]+?						// list item text   = $4

-			(\n{1,2}))

-			(?= \n* (~0 | \2 ([*+-]|\d+[.]) [ \t]+))

-		/gm, function(){...});

-	*/

-	list_str = list_str.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,

-		function(wholeMatch,m1,m2,m3,m4){

-			var item = m4;

-			var leading_line = m1;

-			var leading_space = m2;

-

-			if (leading_line || (item.search(/\n{2,}/)>-1)) {

-				item = _RunBlockGamut(_Outdent(item));

-			}

-			else {

-				// Recursion for sub-lists:

-				item = _DoLists(_Outdent(item));

-				item = item.replace(/\n$/,""); // chomp(item)

-				item = _RunSpanGamut(item);

-			}

-

-			return  "<li>" + item + "</li>\n";

-		}

-	);

-

-	// attacklab: strip sentinel

-	list_str = list_str.replace(/~0/g,"");

-

-	g_list_level--;

-	return list_str;

-}

-

-

-var _DoCodeBlocks = function(text) {

-//

-//  Process Markdown `<pre><code>` blocks.

-//  

-

-	/*

-		text = text.replace(text,

-			/(?:\n\n|^)

-			(								// $1 = the code block -- one or more lines, starting with a space/tab

-				(?:

-					(?:[ ]{4}|\t)			// Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width

-					.*\n+

-				)+

-			)

-			(\n*[ ]{0,3}[^ \t\n]|(?=~0))	// attacklab: g_tab_width

-		/g,function(){...});

-	*/

-

-	// attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug

-	text += "~0";

-	

-	text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,

-		function(wholeMatch,m1,m2) {

-			var codeblock = m1;

-			var nextChar = m2;

-		

-			codeblock = _EncodeCode( _Outdent(codeblock));

-			codeblock = _Detab(codeblock);

-			codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines

-			codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace

-

-			codeblock = "<pre><code>" + codeblock + "\n</code></pre>";

-

-			return hashBlock(codeblock) + nextChar;

-		}

-	);

-

-	// attacklab: strip sentinel

-	text = text.replace(/~0/,"");

-

-	return text;

-}

-

-var hashBlock = function(text) {

-	text = text.replace(/(^\n+|\n+$)/g,"");

-	return "\n\n~K" + (g_html_blocks.push(text)-1) + "K\n\n";

-}

-

-

-var _DoCodeSpans = function(text) {

-//

-//   *  Backtick quotes are used for <code></code> spans.

-// 

-//   *  You can use multiple backticks as the delimiters if you want to

-//	 include literal backticks in the code span. So, this input:

-//	 

-//		 Just type ``foo `bar` baz`` at the prompt.

-//	 

-//	   Will translate to:

-//	 

-//		 <p>Just type <code>foo `bar` baz</code> at the prompt.</p>

-//	 

-//	There's no arbitrary limit to the number of backticks you

-//	can use as delimters. If you need three consecutive backticks

-//	in your code, use four for delimiters, etc.

-//

-//  *  You can use spaces to get literal backticks at the edges:

-//	 

-//		 ... type `` `bar` `` ...

-//	 

-//	   Turns to:

-//	 

-//		 ... type <code>`bar`</code> ...

-//

-

-	/*

-		text = text.replace(/

-			(^|[^\\])					// Character before opening ` can't be a backslash

-			(`+)						// $2 = Opening run of `

-			(							// $3 = The code block

-				[^\r]*?

-				[^`]					// attacklab: work around lack of lookbehind

-			)

-			\2							// Matching closer

-			(?!`)

-		/gm, function(){...});

-	*/

-

-	text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,

-		function(wholeMatch,m1,m2,m3,m4) {

-			var c = m3;

-			c = c.replace(/^([ \t]*)/g,"");	// leading whitespace

-			c = c.replace(/[ \t]*$/g,"");	// trailing whitespace

-			c = _EncodeCode(c);

-			return m1+"<code>"+c+"</code>";

-		});

-

-	return text;

-}

-

-

-var _EncodeCode = function(text) {

-//

-// Encode/escape certain characters inside Markdown code runs.

-// The point is that in code, these characters are literals,

-// and lose their special Markdown meanings.

-//

-	// Encode all ampersands; HTML entities are not

-	// entities within a Markdown code span.

-	text = text.replace(/&/g,"&amp;");

-

-	// Do the angle bracket song and dance:

-	text = text.replace(/</g,"&lt;");

-	text = text.replace(/>/g,"&gt;");

-

-	// Now, escape characters that are magic in Markdown:

-	text = escapeCharacters(text,"\*_{}[]\\",false);

-

-// jj the line above breaks this:

-//---

-

-//* Item

-

-//   1. Subitem

-

-//            special char: *

-//---

-

-	return text;

-}

-

-

-var _DoItalicsAndBold = function(text) {

-

-	// <strong> must go first:

-	text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,

-		"<strong>$2</strong>");

-

-	text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,

-		"<em>$2</em>");

-

-	return text;

-}

-

-

-var _DoBlockQuotes = function(text) {

-

-	/*

-		text = text.replace(/

-		(								// Wrap whole match in $1

-			(

-				^[ \t]*>[ \t]?			// '>' at the start of a line

-				.+\n					// rest of the first line

-				(.+\n)*					// subsequent consecutive lines

-				\n*						// blanks

-			)+

-		)

-		/gm, function(){...});

-	*/

-

-	text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,

-		function(wholeMatch,m1) {

-			var bq = m1;

-

-			// attacklab: hack around Konqueror 3.5.4 bug:

-			// "----------bug".replace(/^-/g,"") == "bug"

-

-			bq = bq.replace(/^[ \t]*>[ \t]?/gm,"~0");	// trim one level of quoting

-

-			// attacklab: clean up hack

-			bq = bq.replace(/~0/g,"");

-

-			bq = bq.replace(/^[ \t]+$/gm,"");		// trim whitespace-only lines

-			bq = _RunBlockGamut(bq);				// recurse

-			

-			bq = bq.replace(/(^|\n)/g,"$1  ");

-			// These leading spaces screw with <pre> content, so we need to fix that:

-			bq = bq.replace(

-					/(\s*<pre>[^\r]+?<\/pre>)/gm,

-				function(wholeMatch,m1) {

-					var pre = m1;

-					// attacklab: hack around Konqueror 3.5.4 bug:

-					pre = pre.replace(/^  /mg,"~0");

-					pre = pre.replace(/~0/g,"");

-					return pre;

-				});

-			

-			return hashBlock("<blockquote>\n" + bq + "\n</blockquote>");

-		});

-	return text;

-}

-

-

-var _FormParagraphs = function(text) {

-//

-//  Params:

-//    $text - string to process with html <p> tags

-//

-

-	// Strip leading and trailing lines:

-	text = text.replace(/^\n+/g,"");

-	text = text.replace(/\n+$/g,"");

-

-	var grafs = text.split(/\n{2,}/g);

-	var grafsOut = new Array();

-

-	//

-	// Wrap <p> tags.

-	//

-	var end = grafs.length;

-	for (var i=0; i<end; i++) {

-		var str = grafs[i];

-

-		// if this is an HTML marker, copy it

-		if (str.search(/~K(\d+)K/g) >= 0) {

-			grafsOut.push(str);

-		}

-		else if (str.search(/\S/) >= 0) {

-			str = _RunSpanGamut(str);

-			str = str.replace(/^([ \t]*)/g,"<p>");

-			str += "</p>"

-			grafsOut.push(str);

-		}

-

-	}

-

-	//

-	// Unhashify HTML blocks

-	//

-	end = grafsOut.length;

-	for (var i=0; i<end; i++) {

-		// if this is a marker for an html block...

-		while (grafsOut[i].search(/~K(\d+)K/) >= 0) {

-			var blockText = g_html_blocks[RegExp.$1];

-			blockText = blockText.replace(/\$/g,"$$$$"); // Escape any dollar signs

-			grafsOut[i] = grafsOut[i].replace(/~K\d+K/,blockText);

-		}

-	}

-

-	return grafsOut.join("\n\n");

-}

-

-

-var _EncodeAmpsAndAngles = function(text) {

-// Smart processing for ampersands and angle brackets that need to be encoded.

-	

-	// Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:

-	//   http://bumppo.net/projects/amputator/

-	text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&amp;");

-	

-	// Encode naked <'s

-	text = text.replace(/<(?![a-z\/?\$!])/gi,"&lt;");

-	

-	return text;

-}

-

-

-var _EncodeBackslashEscapes = function(text) {

-//

-//   Parameter:  String.

-//   Returns:	The string, with after processing the following backslash

-//			   escape sequences.

-//

-

-	// attacklab: The polite way to do this is with the new

-	// escapeCharacters() function:

-	//

-	// 	text = escapeCharacters(text,"\\",true);

-	// 	text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);

-	//

-	// ...but we're sidestepping its use of the (slow) RegExp constructor

-	// as an optimization for Firefox.  This function gets called a LOT.

-

-	text = text.replace(/\\(\\)/g,escapeCharacters_callback);

-	text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g,escapeCharacters_callback);

-	return text;

-}

-

-

-var _DoAutoLinks = function(text) {

-

-	text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"<a href=\"$1\">$1</a>");

-

-	// Email addresses: <address@domain.foo>

-

-	/*

-		text = text.replace(/

-			<

-			(?:mailto:)?

-			(

-				[-.\w]+

-				\@

-				[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+

-			)

-			>

-		/gi, _DoAutoLinks_callback());

-	*/

-	text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,

-		function(wholeMatch,m1) {

-			return _EncodeEmailAddress( _UnescapeSpecialChars(m1) );

-		}

-	);

-

-	return text;

-}

-

-

-var _EncodeEmailAddress = function(addr) {

-//

-//  Input: an email address, e.g. "foo@example.com"

-//

-//  Output: the email address as a mailto link, with each character

-//	of the address encoded as either a decimal or hex entity, in

-//	the hopes of foiling most address harvesting spam bots. E.g.:

-//

-//	<a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;

-//	   x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;

-//	   &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>

-//

-//  Based on a filter by Matthew Wickline, posted to the BBEdit-Talk

-//  mailing list: <http://tinyurl.com/yu7ue>

-//

-

-	// attacklab: why can't javascript speak hex?

-	function char2hex(ch) {

-		var hexDigits = '0123456789ABCDEF';

-		var dec = ch.charCodeAt(0);

-		return(hexDigits.charAt(dec>>4) + hexDigits.charAt(dec&15));

-	}

-

-	var encode = [

-		function(ch){return "&#"+ch.charCodeAt(0)+";";},

-		function(ch){return "&#x"+char2hex(ch)+";";},

-		function(ch){return ch;}

-	];

-

-	addr = "mailto:" + addr;

-

-	addr = addr.replace(/./g, function(ch) {

-		if (ch == "@") {

-		   	// this *must* be encoded. I insist.

-			ch = encode[Math.floor(Math.random()*2)](ch);

-		} else if (ch !=":") {

-			// leave ':' alone (to spot mailto: later)

-			var r = Math.random();

-			// roughly 10% raw, 45% hex, 45% dec

-			ch =  (

-					r > .9  ?	encode[2](ch)   :

-					r > .45 ?	encode[1](ch)   :

-								encode[0](ch)

-				);

-		}

-		return ch;

-	});

-

-	addr = "<a href=\"" + addr + "\">" + addr + "</a>";

-	addr = addr.replace(/">.+:/g,"\">"); // strip the mailto: from the visible part

-

-	return addr;

-}

-

-

-var _UnescapeSpecialChars = function(text) {

-//

-// Swap back in all the special characters we've hidden.

-//

-	text = text.replace(/~E(\d+)E/g,

-		function(wholeMatch,m1) {

-			var charCodeToReplace = parseInt(m1);

-			return String.fromCharCode(charCodeToReplace);

-		}

-	);

-	return text;

-}

-

-

-var _Outdent = function(text) {

-//

-// Remove one level of line-leading tabs or spaces

-//

-

-	// attacklab: hack around Konqueror 3.5.4 bug:

-	// "----------bug".replace(/^-/g,"") == "bug"

-

-	text = text.replace(/^(\t|[ ]{1,4})/gm,"~0"); // attacklab: g_tab_width

-

-	// attacklab: clean up hack

-	text = text.replace(/~0/g,"")

-

-	return text;

-}

-

-var _Detab = function(text) {

-// attacklab: Detab's completely rewritten for speed.

-// In perl we could fix it by anchoring the regexp with \G.

-// In javascript we're less fortunate.

-

-	// expand first n-1 tabs

-	text = text.replace(/\t(?=\t)/g,"    "); // attacklab: g_tab_width

-

-	// replace the nth with two sentinels

-	text = text.replace(/\t/g,"~A~B");

-

-	// use the sentinel to anchor our regex so it doesn't explode

-	text = text.replace(/~B(.+?)~A/g,

-		function(wholeMatch,m1,m2) {

-			var leadingText = m1;

-			var numSpaces = 4 - leadingText.length % 4;  // attacklab: g_tab_width

-

-			// there *must* be a better way to do this:

-			for (var i=0; i<numSpaces; i++) leadingText+=" ";

-

-			return leadingText;

-		}

-	);

-

-	// clean up sentinels

-	text = text.replace(/~A/g,"    ");  // attacklab: g_tab_width

-	text = text.replace(/~B/g,"");

-

-	return text;

-}

-

-

-//

-//  attacklab: Utility functions

-//

-

-

-var escapeCharacters = function(text, charsToEscape, afterBackslash) {

-	// First we have to escape the escape characters so that

-	// we can build a character class out of them

-	var regexString = "([" + charsToEscape.replace(/([\[\]\\])/g,"\\$1") + "])";

-

-	if (afterBackslash) {

-		regexString = "\\\\" + regexString;

-	}

-

-	var regex = new RegExp(regexString,"g");

-	text = text.replace(regex,escapeCharacters_callback);

-

-	return text;

-}

-

-

-var escapeCharacters_callback = function(wholeMatch,m1) {

-	var charCodeToEscape = m1.charCodeAt(0);

-	return "~E"+charCodeToEscape+"E";

-}

-

-} // end of Showdown.converter

-

-// export

-if (typeof exports != 'undefined') exports.Showdown = Showdown;

+//
+// showdown.js -- A javascript port of Markdown.
+//
+// Copyright (c) 2007 John Fraser.
+//
+// Original Markdown Copyright (c) 2004-2005 John Gruber
+//   <http://daringfireball.net/projects/markdown/>
+//
+// Redistributable under a BSD-style open source license.
+// See license.txt for more information.
+//
+// The full source distribution is at:
+//
+//				A A L
+//				T C A
+//				T K B
+//
+//   <http://www.attacklab.net/>
+//
+
+//
+// Wherever possible, Showdown is a straight, line-by-line port
+// of the Perl version of Markdown.
+//
+// This is not a normal parser design; it's basically just a
+// series of string substitutions.  It's hard to read and
+// maintain this way,  but keeping Showdown close to the original
+// design makes it easier to port new features.
+//
+// More importantly, Showdown behaves like markdown.pl in most
+// edge cases.  So web applications can do client-side preview
+// in Javascript, and then build identical HTML on the server.
+//
+// This port needs the new RegExp functionality of ECMA 262,
+// 3rd Edition (i.e. Javascript 1.5).  Most modern web browsers
+// should do fine.  Even with the new regular expression features,
+// We do a lot of work to emulate Perl's regex functionality.
+// The tricky changes in this file mostly have the "attacklab:"
+// label.  Major or self-explanatory changes don't.
+//
+// Smart diff tools like Araxis Merge will be able to match up
+// this file with markdown.pl in a useful way.  A little tweaking
+// helps: in a copy of markdown.pl, replace "#" with "//" and
+// replace "$text" with "text".  Be sure to ignore whitespace
+// and line endings.
+//
+
+
+//
+// Showdown usage:
+//
+//   var text = "Markdown *rocks*.";
+//
+//   var converter = new Showdown.converter();
+//   var html = converter.makeHtml(text);
+//
+//   alert(html);
+//
+// Note: move the sample code to the bottom of this
+// file before uncommenting it.
+//
+
+
+//
+// Showdown namespace
+//
+var Showdown = {};
+
+//
+// converter
+//
+// Wraps all "globals" so that the only thing
+// exposed is makeHtml().
+//
+Showdown.converter = function() {
+
+//
+// Globals:
+//
+
+// Global hashes, used by various utility routines
+var g_urls;
+var g_titles;
+var g_html_blocks;
+
+// Used to track when we're inside an ordered or unordered list
+// (see _ProcessListItems() for details):
+var g_list_level = 0;
+
+
+this.makeHtml = function(text) {
+//
+// Main function. The order in which other subs are called here is
+// essential. Link and image substitutions need to happen before
+// _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the <a>
+// and <img> tags get encoded.
+//
+
+	// Clear the global hashes. If we don't clear these, you get conflicts
+	// from other articles when generating a page which contains more than
+	// one article (e.g. an index page that shows the N most recent
+	// articles):
+	g_urls = new Array();
+	g_titles = new Array();
+	g_html_blocks = new Array();
+
+	// attacklab: Replace ~ with ~T
+	// This lets us use tilde as an escape char to avoid md5 hashes
+	// The choice of character is arbitray; anything that isn't
+    // magic in Markdown will work.
+	text = text.replace(/~/g,"~T");
+
+	// attacklab: Replace $ with ~D
+	// RegExp interprets $ as a special character
+	// when it's in a replacement string
+	text = text.replace(/\$/g,"~D");
+
+	// Standardize line endings
+	text = text.replace(/\r\n/g,"\n"); // DOS to Unix
+	text = text.replace(/\r/g,"\n"); // Mac to Unix
+
+	// Make sure text begins and ends with a couple of newlines:
+	text = "\n\n" + text + "\n\n";
+
+	// Convert all tabs to spaces.
+	text = _Detab(text);
+
+	// Strip any lines consisting only of spaces and tabs.
+	// This makes subsequent regexen easier to write, because we can
+	// match consecutive blank lines with /\n+/ instead of something
+	// contorted like /[ \t]*\n+/ .
+	text = text.replace(/^[ \t]+$/mg,"");
+
+	// Turn block-level HTML blocks into hash entries
+	text = _HashHTMLBlocks(text);
+
+	// Strip link definitions, store in hashes.
+	text = _StripLinkDefinitions(text);
+
+	text = _RunBlockGamut(text);
+
+	text = _UnescapeSpecialChars(text);
+
+	// attacklab: Restore dollar signs
+	text = text.replace(/~D/g,"$$");
+
+	// attacklab: Restore tildes
+	text = text.replace(/~T/g,"~");
+
+	return text;
+}
+
+
+var _StripLinkDefinitions = function(text) {
+//
+// Strips link definitions from text, stores the URLs and titles in
+// hash references.
+//
+
+	// Link defs are in the form: ^[id]: url "optional title"
+
+	/*
+		var text = text.replace(/
+				^[ ]{0,3}\[(.+)\]:  // id = $1  attacklab: g_tab_width - 1
+				  [ \t]*
+				  \n?				// maybe *one* newline
+				  [ \t]*
+				<?(\S+?)>?			// url = $2
+				  [ \t]*
+				  \n?				// maybe one newline
+				  [ \t]*
+				(?:
+				  (\n*)				// any lines skipped = $3 attacklab: lookbehind removed
+				  ["(]
+				  (.+?)				// title = $4
+				  [")]
+				  [ \t]*
+				)?					// title is optional
+				(?:\n+|$)
+			  /gm,
+			  function(){...});
+	*/
+	var text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|\Z)/gm,
+		function (wholeMatch,m1,m2,m3,m4) {
+			m1 = m1.toLowerCase();
+			g_urls[m1] = _EncodeAmpsAndAngles(m2);  // Link IDs are case-insensitive
+			if (m3) {
+				// Oops, found blank lines, so it's not a title.
+				// Put back the parenthetical statement we stole.
+				return m3+m4;
+			} else if (m4) {
+				g_titles[m1] = m4.replace(/"/g,"&quot;");
+			}
+			
+			// Completely remove the definition from the text
+			return "";
+		}
+	);
+
+	return text;
+}
+
+
+var _HashHTMLBlocks = function(text) {
+	// attacklab: Double up blank lines to reduce lookaround
+	text = text.replace(/\n/g,"\n\n");
+
+	// Hashify HTML blocks:
+	// We only want to do this for block-level HTML tags, such as headers,
+	// lists, and tables. That's because we still want to wrap <p>s around
+	// "paragraphs" that are wrapped in non-block-level tags, such as anchors,
+	// phrase emphasis, and spans. The list of tags we're looking for is
+	// hard-coded:
+	var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"
+	var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math"
+
+	// First, look for nested blocks, e.g.:
+	//   <div>
+	//     <div>
+	//     tags for inner block must be indented.
+	//     </div>
+	//   </div>
+	//
+	// The outermost tags must start at the left margin for this to match, and
+	// the inner nested divs must be indented.
+	// We need to do this before the next, more liberal match, because the next
+	// match will start at the first `<div>` and stop at the first `</div>`.
+
+	// attacklab: This regex can be expensive when it fails.
+	/*
+		var text = text.replace(/
+		(						// save in $1
+			^					// start of line  (with /m)
+			<($block_tags_a)	// start tag = $2
+			\b					// word break
+								// attacklab: hack around khtml/pcre bug...
+			[^\r]*?\n			// any number of lines, minimally matching
+			</\2>				// the matching end tag
+			[ \t]*				// trailing spaces/tabs
+			(?=\n+)				// followed by a newline
+		)						// attacklab: there are sentinel newlines at end of document
+		/gm,function(){...}};
+	*/
+	text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,hashElement);
+
+	//
+	// Now match more liberally, simply from `\n<tag>` to `</tag>\n`
+	//
+
+	/*
+		var text = text.replace(/
+		(						// save in $1
+			^					// start of line  (with /m)
+			<($block_tags_b)	// start tag = $2
+			\b					// word break
+								// attacklab: hack around khtml/pcre bug...
+			[^\r]*?				// any number of lines, minimally matching
+			.*</\2>				// the matching end tag
+			[ \t]*				// trailing spaces/tabs
+			(?=\n+)				// followed by a newline
+		)						// attacklab: there are sentinel newlines at end of document
+		/gm,function(){...}};
+	*/
+	text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm,hashElement);
+
+	// Special case just for <hr />. It was easier to make a special case than
+	// to make the other regex more complicated.  
+
+	/*
+		text = text.replace(/
+		(						// save in $1
+			\n\n				// Starting after a blank line
+			[ ]{0,3}
+			(<(hr)				// start tag = $2
+			\b					// word break
+			([^<>])*?			// 
+			\/?>)				// the matching end tag
+			[ \t]*
+			(?=\n{2,})			// followed by a blank line
+		)
+		/g,hashElement);
+	*/
+	text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,hashElement);
+
+	// Special case for standalone HTML comments:
+
+	/*
+		text = text.replace(/
+		(						// save in $1
+			\n\n				// Starting after a blank line
+			[ ]{0,3}			// attacklab: g_tab_width - 1
+			<!
+			(--[^\r]*?--\s*)+
+			>
+			[ \t]*
+			(?=\n{2,})			// followed by a blank line
+		)
+		/g,hashElement);
+	*/
+	text = text.replace(/(\n\n[ ]{0,3}<!(--[^\r]*?--\s*)+>[ \t]*(?=\n{2,}))/g,hashElement);
+
+	// PHP and ASP-style processor instructions (<?...?> and <%...%>)
+
+	/*
+		text = text.replace(/
+		(?:
+			\n\n				// Starting after a blank line
+		)
+		(						// save in $1
+			[ ]{0,3}			// attacklab: g_tab_width - 1
+			(?:
+				<([?%])			// $2
+				[^\r]*?
+				\2>
+			)
+			[ \t]*
+			(?=\n{2,})			// followed by a blank line
+		)
+		/g,hashElement);
+	*/
+	text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,hashElement);
+
+	// attacklab: Undo double lines (see comment at top of this function)
+	text = text.replace(/\n\n/g,"\n");
+	return text;
+}
+
+var hashElement = function(wholeMatch,m1) {
+	var blockText = m1;
+
+	// Undo double lines
+	blockText = blockText.replace(/\n\n/g,"\n");
+	blockText = blockText.replace(/^\n/,"");
+	
+	// strip trailing blank lines
+	blockText = blockText.replace(/\n+$/g,"");
+	
+	// Replace the element text with a marker ("~KxK" where x is its key)
+	blockText = "\n\n~K" + (g_html_blocks.push(blockText)-1) + "K\n\n";
+	
+	return blockText;
+};
+
+var _RunBlockGamut = function(text) {
+//
+// These are all the transformations that form block-level
+// tags like paragraphs, headers, and list items.
+//
+	text = _DoHeaders(text);
+
+	// Do Horizontal Rules:
+	var key = hashBlock("<hr />");
+	text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,key);
+	text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,key);
+	text = text.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,key);
+
+	text = _DoLists(text);
+	text = _DoCodeBlocks(text);
+	text = _DoBlockQuotes(text);
+
+	// We already ran _HashHTMLBlocks() before, in Markdown(), but that
+	// was to escape raw HTML in the original Markdown source. This time,
+	// we're escaping the markup we've just created, so that we don't wrap
+	// <p> tags around block-level tags.
+	text = _HashHTMLBlocks(text);
+	text = _FormParagraphs(text);
+
+	return text;
+}
+
+
+var _RunSpanGamut = function(text) {
+//
+// These are all the transformations that occur *within* block-level
+// tags like paragraphs, headers, and list items.
+//
+
+	text = _DoCodeSpans(text);
+	text = _EscapeSpecialCharsWithinTagAttributes(text);
+	text = _EncodeBackslashEscapes(text);
+
+	// Process anchor and image tags. Images must come first,
+	// because ![foo][f] looks like an anchor.
+	text = _DoImages(text);
+	text = _DoAnchors(text);
+
+	// Make links out of things like `<http://example.com/>`
+	// Must come after _DoAnchors(), because you can use < and >
+	// delimiters in inline links like [this](<url>).
+	text = _DoAutoLinks(text);
+	text = _EncodeAmpsAndAngles(text);
+	text = _DoItalicsAndBold(text);
+
+	// Do hard breaks:
+	text = text.replace(/  +\n/g," <br />\n");
+
+	return text;
+}
+
+var _EscapeSpecialCharsWithinTagAttributes = function(text) {
+//
+// Within tags -- meaning between < and > -- encode [\ ` * _] so they
+// don't conflict with their use in Markdown for code, italics and strong.
+//
+
+	// Build a regex to find HTML tags and comments.  See Friedl's 
+	// "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
+	var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;
+
+	text = text.replace(regex, function(wholeMatch) {
+		var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`");
+		tag = escapeCharacters(tag,"\\`*_");
+		return tag;
+	});
+
+	return text;
+}
+
+var _DoAnchors = function(text) {
+//
+// Turn Markdown link shortcuts into XHTML <a> tags.
+//
+	//
+	// First, handle reference-style links: [link text] [id]
+	//
+
+	/*
+		text = text.replace(/
+		(							// wrap whole match in $1
+			\[
+			(
+				(?:
+					\[[^\]]*\]		// allow brackets nested one level
+					|
+					[^\[]			// or anything else
+				)*
+			)
+			\]
+
+			[ ]?					// one optional space
+			(?:\n[ ]*)?				// one optional newline followed by spaces
+
+			\[
+			(.*?)					// id = $3
+			\]
+		)()()()()					// pad remaining backreferences
+		/g,_DoAnchors_callback);
+	*/
+	text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag);
+
+	//
+	// Next, inline-style links: [link text](url "optional title")
+	//
+
+	/*
+		text = text.replace(/
+			(						// wrap whole match in $1
+				\[
+				(
+					(?:
+						\[[^\]]*\]	// allow brackets nested one level
+					|
+					[^\[\]]			// or anything else
+				)
+			)
+			\]
+			\(						// literal paren
+			[ \t]*
+			()						// no id, so leave $3 empty
+			<?(.*?)>?				// href = $4
+			[ \t]*
+			(						// $5
+				(['"])				// quote char = $6
+				(.*?)				// Title = $7
+				\6					// matching quote
+				[ \t]*				// ignore any spaces/tabs between closing quote and )
+			)?						// title is optional
+			\)
+		)
+		/g,writeAnchorTag);
+	*/
+	text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag);
+
+	//
+	// Last, handle reference-style shortcuts: [link text]
+	// These must come last in case you've also got [link test][1]
+	// or [link test](/foo)
+	//
+
+	/*
+		text = text.replace(/
+		(		 					// wrap whole match in $1
+			\[
+			([^\[\]]+)				// link text = $2; can't contain '[' or ']'
+			\]
+		)()()()()()					// pad rest of backreferences
+		/g, writeAnchorTag);
+	*/
+	text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
+
+	return text;
+}
+
+var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
+	if (m7 == undefined) m7 = "";
+	var whole_match = m1;
+	var link_text   = m2;
+	var link_id	 = m3.toLowerCase();
+	var url		= m4;
+	var title	= m7;
+	
+	if (url == "") {
+		if (link_id == "") {
+			// lower-case and turn embedded newlines into spaces
+			link_id = link_text.toLowerCase().replace(/ ?\n/g," ");
+		}
+		url = "#"+link_id;
+		
+		if (g_urls[link_id] != undefined) {
+			url = g_urls[link_id];
+			if (g_titles[link_id] != undefined) {
+				title = g_titles[link_id];
+			}
+		}
+		else {
+			if (whole_match.search(/\(\s*\)$/m)>-1) {
+				// Special case for explicit empty url
+				url = "";
+			} else {
+				return whole_match;
+			}
+		}
+	}	
+	
+	url = escapeCharacters(url,"*_");
+	var result = "<a href=\"" + url + "\"";
+	
+	if (title != "") {
+		title = title.replace(/"/g,"&quot;");
+		title = escapeCharacters(title,"*_");
+		result +=  " title=\"" + title + "\"";
+	}
+	
+	result += ">" + link_text + "</a>";
+	
+	return result;
+}
+
+
+var _DoImages = function(text) {
+//
+// Turn Markdown image shortcuts into <img> tags.
+//
+
+	//
+	// First, handle reference-style labeled images: ![alt text][id]
+	//
+
+	/*
+		text = text.replace(/
+		(						// wrap whole match in $1
+			!\[
+			(.*?)				// alt text = $2
+			\]
+
+			[ ]?				// one optional space
+			(?:\n[ ]*)?			// one optional newline followed by spaces
+
+			\[
+			(.*?)				// id = $3
+			\]
+		)()()()()				// pad rest of backreferences
+		/g,writeImageTag);
+	*/
+	text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag);
+
+	//
+	// Next, handle inline images:  ![alt text](url "optional title")
+	// Don't forget: encode * and _
+
+	/*
+		text = text.replace(/
+		(						// wrap whole match in $1
+			!\[
+			(.*?)				// alt text = $2
+			\]
+			\s?					// One optional whitespace character
+			\(					// literal paren
+			[ \t]*
+			()					// no id, so leave $3 empty
+			<?(\S+?)>?			// src url = $4
+			[ \t]*
+			(					// $5
+				(['"])			// quote char = $6
+				(.*?)			// title = $7
+				\6				// matching quote
+				[ \t]*
+			)?					// title is optional
+		\)
+		)
+		/g,writeImageTag);
+	*/
+	text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag);
+
+	return text;
+}
+
+var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
+	var whole_match = m1;
+	var alt_text   = m2;
+	var link_id	 = m3.toLowerCase();
+	var url		= m4;
+	var title	= m7;
+
+	if (!title) title = "";
+	
+	if (url == "") {
+		if (link_id == "") {
+			// lower-case and turn embedded newlines into spaces
+			link_id = alt_text.toLowerCase().replace(/ ?\n/g," ");
+		}
+		url = "#"+link_id;
+		
+		if (g_urls[link_id] != undefined) {
+			url = g_urls[link_id];
+			if (g_titles[link_id] != undefined) {
+				title = g_titles[link_id];
+			}
+		}
+		else {
+			return whole_match;
+		}
+	}	
+	
+	alt_text = alt_text.replace(/"/g,"&quot;");
+	url = escapeCharacters(url,"*_");
+	var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\"";
+
+	// attacklab: Markdown.pl adds empty title attributes to images.
+	// Replicate this bug.
+
+	//if (title != "") {
+		title = title.replace(/"/g,"&quot;");
+		title = escapeCharacters(title,"*_");
+		result +=  " title=\"" + title + "\"";
+	//}
+	
+	result += " />";
+	
+	return result;
+}
+
+
+var _DoHeaders = function(text) {
+
+	// Setext-style headers:
+	//	Header 1
+	//	========
+	//  
+	//	Header 2
+	//	--------
+	//
+	text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,
+		function(wholeMatch,m1){return hashBlock('<h1 id="' + headerId(m1) + '">' + _RunSpanGamut(m1) + "</h1>");});
+
+	text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,
+		function(matchFound,m1){return hashBlock('<h2 id="' + headerId(m1) + '">' + _RunSpanGamut(m1) + "</h2>");});
+
+	// atx-style headers:
+	//  # Header 1
+	//  ## Header 2
+	//  ## Header 2 with closing hashes ##
+	//  ...
+	//  ###### Header 6
+	//
+
+	/*
+		text = text.replace(/
+			^(\#{1,6})				// $1 = string of #'s
+			[ \t]*
+			(.+?)					// $2 = Header text
+			[ \t]*
+			\#*						// optional closing #'s (not counted)
+			\n+
+		/gm, function() {...});
+	*/
+
+	text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,
+		function(wholeMatch,m1,m2) {
+			var h_level = m1.length;
+			return hashBlock("<h" + h_level + ' id="' + headerId(m2) + '">' + _RunSpanGamut(m2) + "</h" + h_level + ">");
+		});
+
+	function headerId(m) {
+		return m.replace(/[^\w]/g, '').toLowerCase();
+	}
+	return text;
+}
+
+// This declaration keeps Dojo compressor from outputting garbage:
+var _ProcessListItems;
+
+var _DoLists = function(text) {
+//
+// Form HTML ordered (numbered) and unordered (bulleted) lists.
+//
+
+	// attacklab: add sentinel to hack around khtml/safari bug:
+	// http://bugs.webkit.org/show_bug.cgi?id=11231
+	text += "~0";
+
+	// Re-usable pattern to match any entirel ul or ol list:
+
+	/*
+		var whole_list = /
+		(									// $1 = whole list
+			(								// $2
+				[ ]{0,3}					// attacklab: g_tab_width - 1
+				([*+-]|\d+[.])				// $3 = first list item marker
+				[ \t]+
+			)
+			[^\r]+?
+			(								// $4
+				~0							// sentinel for workaround; should be $
+			|
+				\n{2,}
+				(?=\S)
+				(?!							// Negative lookahead for another list item marker
+					[ \t]*
+					(?:[*+-]|\d+[.])[ \t]+
+				)
+			)
+		)/g
+	*/
+	var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
+
+	if (g_list_level) {
+		text = text.replace(whole_list,function(wholeMatch,m1,m2) {
+			var list = m1;
+			var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol";
+
+			// Turn double returns into triple returns, so that we can make a
+			// paragraph for the last item in a list, if necessary:
+			list = list.replace(/\n{2,}/g,"\n\n\n");;
+			var result = _ProcessListItems(list);
+	
+			// Trim any trailing whitespace, to put the closing `</$list_type>`
+			// up on the preceding line, to get it past the current stupid
+			// HTML block parser. This is a hack to work around the terrible
+			// hack that is the HTML block parser.
+			result = result.replace(/\s+$/,"");
+			result = "<"+list_type+">" + result + "</"+list_type+">\n";
+			return result;
+		});
+	} else {
+		whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g;
+		text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) {
+			var runup = m1;
+			var list = m2;
+
+			var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol";
+			// Turn double returns into triple returns, so that we can make a
+			// paragraph for the last item in a list, if necessary:
+			var list = list.replace(/\n{2,}/g,"\n\n\n");;
+			var result = _ProcessListItems(list);
+			result = runup + "<"+list_type+">\n" + result + "</"+list_type+">\n";	
+			return result;
+		});
+	}
+
+	// attacklab: strip sentinel
+	text = text.replace(/~0/,"");
+
+	return text;
+}
+
+_ProcessListItems = function(list_str) {
+//
+//  Process the contents of a single ordered or unordered list, splitting it
+//  into individual list items.
+//
+	// The $g_list_level global keeps track of when we're inside a list.
+	// Each time we enter a list, we increment it; when we leave a list,
+	// we decrement. If it's zero, we're not in a list anymore.
+	//
+	// We do this because when we're not inside a list, we want to treat
+	// something like this:
+	//
+	//    I recommend upgrading to version
+	//    8. Oops, now this line is treated
+	//    as a sub-list.
+	//
+	// As a single paragraph, despite the fact that the second line starts
+	// with a digit-period-space sequence.
+	//
+	// Whereas when we're inside a list (or sub-list), that line will be
+	// treated as the start of a sub-list. What a kludge, huh? This is
+	// an aspect of Markdown's syntax that's hard to parse perfectly
+	// without resorting to mind-reading. Perhaps the solution is to
+	// change the syntax rules such that sub-lists must start with a
+	// starting cardinal number; e.g. "1." or "a.".
+
+	g_list_level++;
+
+	// trim trailing blank lines:
+	list_str = list_str.replace(/\n{2,}$/,"\n");
+
+	// attacklab: add sentinel to emulate \z
+	list_str += "~0";
+
+	/*
+		list_str = list_str.replace(/
+			(\n)?							// leading line = $1
+			(^[ \t]*)						// leading whitespace = $2
+			([*+-]|\d+[.]) [ \t]+			// list marker = $3
+			([^\r]+?						// list item text   = $4
+			(\n{1,2}))
+			(?= \n* (~0 | \2 ([*+-]|\d+[.]) [ \t]+))
+		/gm, function(){...});
+	*/
+	list_str = list_str.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
+		function(wholeMatch,m1,m2,m3,m4){
+			var item = m4;
+			var leading_line = m1;
+			var leading_space = m2;
+
+			if (leading_line || (item.search(/\n{2,}/)>-1)) {
+				item = _RunBlockGamut(_Outdent(item));
+			}
+			else {
+				// Recursion for sub-lists:
+				item = _DoLists(_Outdent(item));
+				item = item.replace(/\n$/,""); // chomp(item)
+				item = _RunSpanGamut(item);
+			}
+
+			return  "<li>" + item + "</li>\n";
+		}
+	);
+
+	// attacklab: strip sentinel
+	list_str = list_str.replace(/~0/g,"");
+
+	g_list_level--;
+	return list_str;
+}
+
+
+var _DoCodeBlocks = function(text) {
+//
+//  Process Markdown `<pre><code>` blocks.
+//  
+
+	/*
+		text = text.replace(text,
+			/(?:\n\n|^)
+			(								// $1 = the code block -- one or more lines, starting with a space/tab
+				(?:
+					(?:[ ]{4}|\t)			// Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
+					.*\n+
+				)+
+			)
+			(\n*[ ]{0,3}[^ \t\n]|(?=~0))	// attacklab: g_tab_width
+		/g,function(){...});
+	*/
+
+	// attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
+	text += "~0";
+	
+	text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
+		function(wholeMatch,m1,m2) {
+			var codeblock = m1;
+			var nextChar = m2;
+		
+			codeblock = _EncodeCode( _Outdent(codeblock));
+			codeblock = _Detab(codeblock);
+			codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
+			codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
+
+			codeblock = "<pre><code>" + codeblock + "\n</code></pre>";
+
+			return hashBlock(codeblock) + nextChar;
+		}
+	);
+
+	// attacklab: strip sentinel
+	text = text.replace(/~0/,"");
+
+	return text;
+}
+
+var hashBlock = function(text) {
+	text = text.replace(/(^\n+|\n+$)/g,"");
+	return "\n\n~K" + (g_html_blocks.push(text)-1) + "K\n\n";
+}
+
+
+var _DoCodeSpans = function(text) {
+//
+//   *  Backtick quotes are used for <code></code> spans.
+// 
+//   *  You can use multiple backticks as the delimiters if you want to
+//	 include literal backticks in the code span. So, this input:
+//	 
+//		 Just type ``foo `bar` baz`` at the prompt.
+//	 
+//	   Will translate to:
+//	 
+//		 <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
+//	 
+//	There's no arbitrary limit to the number of backticks you
+//	can use as delimters. If you need three consecutive backticks
+//	in your code, use four for delimiters, etc.
+//
+//  *  You can use spaces to get literal backticks at the edges:
+//	 
+//		 ... type `` `bar` `` ...
+//	 
+//	   Turns to:
+//	 
+//		 ... type <code>`bar`</code> ...
+//
+
+	/*
+		text = text.replace(/
+			(^|[^\\])					// Character before opening ` can't be a backslash
+			(`+)						// $2 = Opening run of `
+			(							// $3 = The code block
+				[^\r]*?
+				[^`]					// attacklab: work around lack of lookbehind
+			)
+			\2							// Matching closer
+			(?!`)
+		/gm, function(){...});
+	*/
+
+	text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
+		function(wholeMatch,m1,m2,m3,m4) {
+			var c = m3;
+			c = c.replace(/^([ \t]*)/g,"");	// leading whitespace
+			c = c.replace(/[ \t]*$/g,"");	// trailing whitespace
+			c = _EncodeCode(c);
+			return m1+"<code>"+c+"</code>";
+		});
+
+	return text;
+}
+
+
+var _EncodeCode = function(text) {
+//
+// Encode/escape certain characters inside Markdown code runs.
+// The point is that in code, these characters are literals,
+// and lose their special Markdown meanings.
+//
+	// Encode all ampersands; HTML entities are not
+	// entities within a Markdown code span.
+	text = text.replace(/&/g,"&amp;");
+
+	// Do the angle bracket song and dance:
+	text = text.replace(/</g,"&lt;");
+	text = text.replace(/>/g,"&gt;");
+
+	// Now, escape characters that are magic in Markdown:
+	text = escapeCharacters(text,"\*_{}[]\\",false);
+
+// jj the line above breaks this:
+//---
+
+//* Item
+
+//   1. Subitem
+
+//            special char: *
+//---
+
+	return text;
+}
+
+
+var _DoItalicsAndBold = function(text) {
+
+	// <strong> must go first:
+	text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,
+		"<strong>$2</strong>");
+
+	text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,
+		"<em>$2</em>");
+
+	return text;
+}
+
+
+var _DoBlockQuotes = function(text) {
+
+	/*
+		text = text.replace(/
+		(								// Wrap whole match in $1
+			(
+				^[ \t]*>[ \t]?			// '>' at the start of a line
+				.+\n					// rest of the first line
+				(.+\n)*					// subsequent consecutive lines
+				\n*						// blanks
+			)+
+		)
+		/gm, function(){...});
+	*/
+
+	text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,
+		function(wholeMatch,m1) {
+			var bq = m1;
+
+			// attacklab: hack around Konqueror 3.5.4 bug:
+			// "----------bug".replace(/^-/g,"") == "bug"
+
+			bq = bq.replace(/^[ \t]*>[ \t]?/gm,"~0");	// trim one level of quoting
+
+			// attacklab: clean up hack
+			bq = bq.replace(/~0/g,"");
+
+			bq = bq.replace(/^[ \t]+$/gm,"");		// trim whitespace-only lines
+			bq = _RunBlockGamut(bq);				// recurse
+			
+			bq = bq.replace(/(^|\n)/g,"$1  ");
+			// These leading spaces screw with <pre> content, so we need to fix that:
+			bq = bq.replace(
+					/(\s*<pre>[^\r]+?<\/pre>)/gm,
+				function(wholeMatch,m1) {
+					var pre = m1;
+					// attacklab: hack around Konqueror 3.5.4 bug:
+					pre = pre.replace(/^  /mg,"~0");
+					pre = pre.replace(/~0/g,"");
+					return pre;
+				});
+			
+			return hashBlock("<blockquote>\n" + bq + "\n</blockquote>");
+		});
+	return text;
+}
+
+
+var _FormParagraphs = function(text) {
+//
+//  Params:
+//    $text - string to process with html <p> tags
+//
+
+	// Strip leading and trailing lines:
+	text = text.replace(/^\n+/g,"");
+	text = text.replace(/\n+$/g,"");
+
+	var grafs = text.split(/\n{2,}/g);
+	var grafsOut = new Array();
+
+	//
+	// Wrap <p> tags.
+	//
+	var end = grafs.length;
+	for (var i=0; i<end; i++) {
+		var str = grafs[i];
+
+		// if this is an HTML marker, copy it
+		if (str.search(/~K(\d+)K/g) >= 0) {
+			grafsOut.push(str);
+		}
+		else if (str.search(/\S/) >= 0) {
+			str = _RunSpanGamut(str);
+			str = str.replace(/^([ \t]*)/g,"<p>");
+			str += "</p>"
+			grafsOut.push(str);
+		}
+
+	}
+
+	//
+	// Unhashify HTML blocks
+	//
+	end = grafsOut.length;
+	for (var i=0; i<end; i++) {
+		// if this is a marker for an html block...
+		while (grafsOut[i].search(/~K(\d+)K/) >= 0) {
+			var blockText = g_html_blocks[RegExp.$1];
+			blockText = blockText.replace(/\$/g,"$$$$"); // Escape any dollar signs
+			grafsOut[i] = grafsOut[i].replace(/~K\d+K/,blockText);
+		}
+	}
+
+	return grafsOut.join("\n\n");
+}
+
+
+var _EncodeAmpsAndAngles = function(text) {
+// Smart processing for ampersands and angle brackets that need to be encoded.
+	
+	// Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
+	//   http://bumppo.net/projects/amputator/
+	text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&amp;");
+	
+	// Encode naked <'s
+	text = text.replace(/<(?![a-z\/?\$!])/gi,"&lt;");
+	
+	return text;
+}
+
+
+var _EncodeBackslashEscapes = function(text) {
+//
+//   Parameter:  String.
+//   Returns:	The string, with after processing the following backslash
+//			   escape sequences.
+//
+
+	// attacklab: The polite way to do this is with the new
+	// escapeCharacters() function:
+	//
+	// 	text = escapeCharacters(text,"\\",true);
+	// 	text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
+	//
+	// ...but we're sidestepping its use of the (slow) RegExp constructor
+	// as an optimization for Firefox.  This function gets called a LOT.
+
+	text = text.replace(/\\(\\)/g,escapeCharacters_callback);
+	text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g,escapeCharacters_callback);
+	return text;
+}
+
+
+var _DoAutoLinks = function(text) {
+
+	text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"<a href=\"$1\">$1</a>");
+
+	// Email addresses: <address@domain.foo>
+
+	/*
+		text = text.replace(/
+			<
+			(?:mailto:)?
+			(
+				[-.\w]+
+				\@
+				[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
+			)
+			>
+		/gi, _DoAutoLinks_callback());
+	*/
+	text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
+		function(wholeMatch,m1) {
+			return _EncodeEmailAddress( _UnescapeSpecialChars(m1) );
+		}
+	);
+
+	return text;
+}
+
+
+var _EncodeEmailAddress = function(addr) {
+//
+//  Input: an email address, e.g. "foo@example.com"
+//
+//  Output: the email address as a mailto link, with each character
+//	of the address encoded as either a decimal or hex entity, in
+//	the hopes of foiling most address harvesting spam bots. E.g.:
+//
+//	<a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;
+//	   x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;
+//	   &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>
+//
+//  Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
+//  mailing list: <http://tinyurl.com/yu7ue>
+//
+
+	// attacklab: why can't javascript speak hex?
+	function char2hex(ch) {
+		var hexDigits = '0123456789ABCDEF';
+		var dec = ch.charCodeAt(0);
+		return(hexDigits.charAt(dec>>4) + hexDigits.charAt(dec&15));
+	}
+
+	var encode = [
+		function(ch){return "&#"+ch.charCodeAt(0)+";";},
+		function(ch){return "&#x"+char2hex(ch)+";";},
+		function(ch){return ch;}
+	];
+
+	addr = "mailto:" + addr;
+
+	addr = addr.replace(/./g, function(ch) {
+		if (ch == "@") {
+		   	// this *must* be encoded. I insist.
+			ch = encode[Math.floor(Math.random()*2)](ch);
+		} else if (ch !=":") {
+			// leave ':' alone (to spot mailto: later)
+			var r = Math.random();
+			// roughly 10% raw, 45% hex, 45% dec
+			ch =  (
+					r > .9  ?	encode[2](ch)   :
+					r > .45 ?	encode[1](ch)   :
+								encode[0](ch)
+				);
+		}
+		return ch;
+	});
+
+	addr = "<a href=\"" + addr + "\">" + addr + "</a>";
+	addr = addr.replace(/">.+:/g,"\">"); // strip the mailto: from the visible part
+
+	return addr;
+}
+
+
+var _UnescapeSpecialChars = function(text) {
+//
+// Swap back in all the special characters we've hidden.
+//
+	text = text.replace(/~E(\d+)E/g,
+		function(wholeMatch,m1) {
+			var charCodeToReplace = parseInt(m1);
+			return String.fromCharCode(charCodeToReplace);
+		}
+	);
+	return text;
+}
+
+
+var _Outdent = function(text) {
+//
+// Remove one level of line-leading tabs or spaces
+//
+
+	// attacklab: hack around Konqueror 3.5.4 bug:
+	// "----------bug".replace(/^-/g,"") == "bug"
+
+	text = text.replace(/^(\t|[ ]{1,4})/gm,"~0"); // attacklab: g_tab_width
+
+	// attacklab: clean up hack
+	text = text.replace(/~0/g,"")
+
+	return text;
+}
+
+var _Detab = function(text) {
+// attacklab: Detab's completely rewritten for speed.
+// In perl we could fix it by anchoring the regexp with \G.
+// In javascript we're less fortunate.
+
+	// expand first n-1 tabs
+	text = text.replace(/\t(?=\t)/g,"    "); // attacklab: g_tab_width
+
+	// replace the nth with two sentinels
+	text = text.replace(/\t/g,"~A~B");
+
+	// use the sentinel to anchor our regex so it doesn't explode
+	text = text.replace(/~B(.+?)~A/g,
+		function(wholeMatch,m1,m2) {
+			var leadingText = m1;
+			var numSpaces = 4 - leadingText.length % 4;  // attacklab: g_tab_width
+
+			// there *must* be a better way to do this:
+			for (var i=0; i<numSpaces; i++) leadingText+=" ";
+
+			return leadingText;
+		}
+	);
+
+	// clean up sentinels
+	text = text.replace(/~A/g,"    ");  // attacklab: g_tab_width
+	text = text.replace(/~B/g,"");
+
+	return text;
+}
+
+
+//
+//  attacklab: Utility functions
+//
+
+
+var escapeCharacters = function(text, charsToEscape, afterBackslash) {
+	// First we have to escape the escape characters so that
+	// we can build a character class out of them
+	var regexString = "([" + charsToEscape.replace(/([\[\]\\])/g,"\\$1") + "])";
+
+	if (afterBackslash) {
+		regexString = "\\\\" + regexString;
+	}
+
+	var regex = new RegExp(regexString,"g");
+	text = text.replace(regex,escapeCharacters_callback);
+
+	return text;
+}
+
+
+var escapeCharacters_callback = function(wholeMatch,m1) {
+	var charCodeToEscape = m1.charCodeAt(0);
+	return "~E"+charCodeToEscape+"E";
+}
+
+} // end of Showdown.converter
+
+// export
+if (typeof exports != 'undefined') exports.Showdown = Showdown;
diff --git a/Editor/src/AutoCorrect.js b/Editor/src/AutoCorrect.js
index 7bb0783..a80e17d 100644
--- a/Editor/src/AutoCorrect.js
+++ b/Editor/src/AutoCorrect.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var AutoCorrect_init;
 var AutoCorrect_removeListeners;
diff --git a/Editor/src/ChangeTracking.js b/Editor/src/ChangeTracking.js
index 9704b17..ba25a44 100644
--- a/Editor/src/ChangeTracking.js
+++ b/Editor/src/ChangeTracking.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var ChangeTracking_showChanges;
 var ChangeTracking_trackChanges;
diff --git a/Editor/src/Clipboard.js b/Editor/src/Clipboard.js
index a0c5381..03efdcc 100644
--- a/Editor/src/Clipboard.js
+++ b/Editor/src/Clipboard.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Markdown_htmlToMarkdown;
 var Clipboard_htmlToText;
diff --git a/Editor/src/Cursor.js b/Editor/src/Cursor.js
index 606c4bd..7362a9e 100644
--- a/Editor/src/Cursor.js
+++ b/Editor/src/Cursor.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Cursor_ensurePositionVisible;
 var Cursor_ensureCursorVisible;
@@ -494,6 +497,39 @@
         Cursor_ensureCursorVisible();
     }
 
+    function tryDeleteEmptyCaption(pos)
+    {
+        var caption = Position_captionAncestor(pos);
+        if ((caption == null) || nodeHasContent(caption))
+            return false;
+
+        var container = Position_figureOrTableAncestor(pos);
+        if (container == null)
+            return false;
+
+        Cursor_set(container.parentNode,DOM_nodeOffset(container)+1);
+        Selection_preserveWhileExecuting(function() {
+            DOM_deleteNode(caption);
+        });
+
+        return true;
+    }
+
+    function tryDeleteEmptyNote(pos)
+    {
+        var note = Position_noteAncestor(pos);
+        if ((note == null) || nodeHasContent(note))
+            return false;
+
+        var parent = note.parentNode;
+        Cursor_set(note.parentNode,DOM_nodeOffset(note)+1);
+        Selection_preserveWhileExecuting(function() {
+            DOM_deleteNode(note);
+        });
+
+        return true;
+    }
+
     // public
     Cursor_deleteCharacter = function()
     {
@@ -511,7 +547,8 @@
         else {
             var currentPos = selRange.start;
 
-            // Special case of pressing backspace after a table, figure, or TOC
+            // Special cases of pressing backspace after a table, figure, TOC, hyperlink,
+            // footnote, or endnote. For each of these we delete the whole thing.
             var back = Position_closestMatchBackwards(currentPos,Position_okForMovement);
             if ((back != null) && (back.node.nodeType == Node.ELEMENT_NODE) && (back.offset > 0)) {
                 var prevNode = back.node.childNodes[back.offset-1];
@@ -524,7 +561,7 @@
                     Cursor_ensureCursorVisible();
                     return;
                 }
-                if (prevNode._type == HTML_A) {
+                if ((prevNode._type == HTML_A) || isNoteNode(prevNode)) {
                     Cursor_set(back.node,back.offset-1);
                     Selection_preserveWhileExecuting(function() {
                         DOM_deleteNode(prevNode);
@@ -533,8 +570,19 @@
                 }
             }
 
+            // Backspace inside an empty figure or table caption
+            if (tryDeleteEmptyCaption(currentPos))
+                return;
+
             currentPos = Position_preferTextPosition(currentPos);
             var prevPos = Position_prevMatch(currentPos,Position_okForMovement);
+
+            // Backspace inside or just after a footnote or endnote
+            if (tryDeleteEmptyNote(currentPos))
+                return;
+            if ((prevPos != null) && tryDeleteEmptyNote(prevPos))
+                return;
+
             if (prevPos != null) {
                 var startBlock = firstBlockAncestor(Position_closestActualNode(prevPos));
                 var endBlock = firstBlockAncestor(Position_closestActualNode(selRange.end));
@@ -606,6 +654,27 @@
             }
         }
 
+        // Are we inside a footnote or endnote? If so, move the cursor immediately after it
+        var note = null;
+        if (selRange.start.node.nodeType == Node.TEXT_NODE) {
+            note = Position_noteAncestor(selRange.start);
+        }
+        else {
+            // We can't use Position_noteAncestor in this case, because we want to to break
+            // the paragraph *before* the note, not after
+            var checkNode = selRange.start.node;
+            for (var anc = checkNode; anc != null; anc = anc.parentNode) {
+                if (isNoteNode(anc)) {
+                    note = anc;
+                    break;
+                }
+            }
+        }
+        if (note != null) {
+            var noteOffset = DOM_nodeOffset(note);
+            selRange = new Range(note.parentNode,noteOffset+1,note.parentNode,noteOffset+1);
+        }
+
         var check = Position_preferElementPosition(selRange.start);
         if (check.node.nodeType == Node.ELEMENT_NODE) {
             var before = check.node.childNodes[check.offset-1];
@@ -802,16 +871,31 @@
     Cursor_getAdjacentNodeWithType = function(type)
     {
         var selRange = Selection_get();
-        var position = selRange.start;
-        while (position != null) {
-            var node = Position_closestActualNode(position);
-            for (; node != null; node = node.parentNode) {
-                if (node._type == type)
-                    return node;
+        var pos = Position_preferElementPosition(selRange.start);
+        var node = pos.node;
+        var offset = pos.offset;
+
+        while (true) {
+
+            if (node._type == type)
+                return node;
+
+            if (node.nodeType == Node.ELEMENT_NODE) {
+                var before = node.childNodes[offset-1];
+                if ((before != null) && (before._type == type))
+                    return before;
+
+                var after = node.childNodes[offset];
+                if ((after != null) && (after._type == type))
+                    return after;
             }
-            position = Position_prev(position);
+
+            if (node.parentNode == null)
+                return null;
+
+            offset = DOM_nodeOffset(node);
+            node = node.parentNode;
         }
-        return null;
     }
 
     Cursor_getLinkProperties = function()
@@ -905,6 +989,22 @@
             cursorX = null;
     }
 
+    function moveRangeOutsideOfNote(range)
+    {
+        var node = range.start.node;
+        var offset = range.start.offset;
+
+        for (var anc = node; anc != null; anc = anc.parentNode) {
+            if (isNoteNode(anc) && (anc.parentNode != null)) {
+                node = anc.parentNode;
+                offset = DOM_nodeOffset(anc)+1;
+                return new Range(node,offset,node,offset);
+            }
+        }
+
+        return range;
+    }
+
     function insertNote(className,content)
     {
         var footnote = DOM_createElement(document,"span");
@@ -912,9 +1012,25 @@
         DOM_appendChild(footnote,DOM_createTextNode(document,content));
 
         var range = Selection_get();
+        range = moveRangeOutsideOfNote(range);
         Formatting_splitAroundSelection(range,false);
 
-        var pos = Position_preferElementPosition(range.start);
+        // If we're part-way through a text node, splitAroundSelection will give us an
+        // empty text node between the before and after text. For formatting purposes that's
+        // fine (not sure if necessary), but when inserting a footnote or endnote we want
+        // to avoid this as it causes problems with cursor movement - specifically, the cursor
+        // is allowed to go inside the empty text node, and this doesn't show up in the correct
+        // position on screen.
+        var pos = range.start;
+        if ((pos.node._type == HTML_TEXT) &&
+            (pos.node.nodeValue.length == 0)) {
+            var empty = pos.node;
+            pos = new Position(empty.parentNode,DOM_nodeOffset(empty));
+            DOM_deleteNode(empty);
+        }
+        else {
+            pos = Position_preferElementPosition(pos);
+        }
 
         DOM_insertBefore(pos.node,footnote,pos.node.childNodes[pos.offset]);
         Selection_set(footnote,0,footnote,footnote.childNodes.length);
diff --git a/Editor/src/DOM.js b/Editor/src/DOM.js
index 723f20e..b2371bc 100644
--- a/Editor/src/DOM.js
+++ b/Editor/src/DOM.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 // Helper functions
 var DOM_assignNodeIds;
diff --git a/Editor/src/Editor.js b/Editor/src/Editor.js
index 88a6ce2..50f0d21 100644
--- a/Editor/src/Editor.js
+++ b/Editor/src/Editor.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Editor_getBackMessages;
 var Editor_debug;
diff --git a/Editor/src/Equations.js b/Editor/src/Equations.js
index d18d21d..46bace8 100644
--- a/Editor/src/Equations.js
+++ b/Editor/src/Equations.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Equations_insertEquation;
 
diff --git a/Editor/src/Figures.js b/Editor/src/Figures.js
index 21c8511..dcda1fc 100644
--- a/Editor/src/Figures.js
+++ b/Editor/src/Figures.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Figures_insertFigure;
 var Figures_getSelectedFigureId;
diff --git a/Editor/src/Formatting.js b/Editor/src/Formatting.js
index 625b928..51bc5d3 100644
--- a/Editor/src/Formatting.js
+++ b/Editor/src/Formatting.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Formatting_splitTextBefore;
 var Formatting_splitTextAfter;
@@ -123,12 +126,12 @@
                 range.start.offset = 0;
             }
             else if (range.start.node.nodeType == Node.ELEMENT_NODE) {
-                Formatting_movePreceding(range.start,isBlockNode);
+                Formatting_movePreceding(range.start,isBlockOrNoteNode);
             }
             else {
                 Formatting_movePreceding(new Position(range.start.node.parentNode,
                                                       DOM_nodeOffset(range.start.node)),
-                                         isBlockNode);
+                                         isBlockOrNoteNode);
             }
 
             // Save the start and end position of the range. The mutation listeners will move it
@@ -143,12 +146,12 @@
                 Formatting_splitTextAfter(range.end);
             }
             else if (range.end.node.nodeType == Node.ELEMENT_NODE) {
-                Formatting_moveFollowing(range.end,isBlockNode);
+                Formatting_moveFollowing(range.end,isBlockOrNoteNode);
             }
             else {
                 Formatting_moveFollowing(new Position(range.end.node.parentNode,
                                                       DOM_nodeOffset(range.end.node)+1),
-                                         isBlockNode);
+                                         isBlockOrNoteNode);
             }
 
             range.start.node = startNode;
@@ -1038,7 +1041,10 @@
         if (span._type == HTML_SPAN) {
             if (span.hasAttribute(Keys.ABSTRACT_ELEMENT))
                 return true;
-            if (DOM_getStringAttribute(span,"class").indexOf(Keys.UXWRITE_PREFIX) == 0)
+            var className = DOM_getStringAttribute(span,"class");
+            if (className.indexOf(Keys.UXWRITE_PREFIX) == 0)
+                return true;
+            if ((className == "footnote") || (className == "endnote"))
                 return true;
         }
         return false;
diff --git a/Editor/src/Hierarchy.js b/Editor/src/Hierarchy.js
index 3151082..07c0526 100644
--- a/Editor/src/Hierarchy.js
+++ b/Editor/src/Hierarchy.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Hierarchy_ensureValidHierarchy;
 var Hierarchy_ensureInlineNodesInParagraph;
diff --git a/Editor/src/Input.js b/Editor/src/Input.js
index 0be1294..db8cb99 100644
--- a/Editor/src/Input.js
+++ b/Editor/src/Input.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Input_removePosition;
 var Input_addPosition;
diff --git a/Editor/src/Lists.js b/Editor/src/Lists.js
index 2a72520..a3a9772 100644
--- a/Editor/src/Lists.js
+++ b/Editor/src/Lists.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Lists_increaseIndent;
 var Lists_decreaseIndent;
diff --git a/Editor/src/Main.js b/Editor/src/Main.js
index 98eccbf..f123423 100644
--- a/Editor/src/Main.js
+++ b/Editor/src/Main.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Main_getLanguage;
 var Main_setLanguage;
diff --git a/Editor/src/Metadata.js b/Editor/src/Metadata.js
index 668c44e..fce4cca 100644
--- a/Editor/src/Metadata.js
+++ b/Editor/src/Metadata.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Metadata_getMetadata;
 var Metadata_setMetadata;
diff --git a/Editor/src/NodeSet.js b/Editor/src/NodeSet.js
index 00e63bc..77b7600 100644
--- a/Editor/src/NodeSet.js
+++ b/Editor/src/NodeSet.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function NodeSet()
 {
diff --git a/Editor/src/Outline.js b/Editor/src/Outline.js
index 4d838df..9812041 100644
--- a/Editor/src/Outline.js
+++ b/Editor/src/Outline.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 // FIXME: The TOC/ItemList stuff won't work with Undo, because we're making DOM mutations in
 // response to other DOM mutations, so at undo time the changes will be made twice
@@ -1099,7 +1102,19 @@
             }
         });
 
+        // Ensure the cursor or selection start/end positions are valid positions that the
+        // user is allowed to move to. This ensures we get an accurate rect for each position,
+        // avoiding an ugly effect where the cursor occupies the entire height of the document
+        // and is displayed on the far-left edge of the editing area.
+        var selRange = Selection_get();
+        if (selRange != null) {
+            var start = Position_closestMatchForwards(selRange.start,Position_okForMovement);
+            var end = Position_closestMatchForwards(selRange.end,Position_okForMovement);
+            Selection_set(start.node,start.offset,end.node,end.offset);
+        }
+
         scheduleUpdateStructure();
+        PostponedActions_add(Cursor_ensureCursorVisible);
         PostponedActions_add(UndoManager_newGroup);
     }
 
diff --git a/Editor/src/Position.js b/Editor/src/Position.js
index 6af3c7b..ce4bc18 100644
--- a/Editor/src/Position.js
+++ b/Editor/src/Position.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Position;
 var Position_assertValid;
@@ -27,6 +30,9 @@
 var Position_track;
 var Position_untrack;
 var Position_rectAtPos;
+var Position_noteAncestor;
+var Position_captionAncestor;
+var Position_figureOrTableAncestor;
 var Position_displayRectAtPos;
 var Position_preferTextPosition;
 var Position_preferElementPosition;
@@ -440,6 +446,7 @@
                 return (haveNextChar &&
                         ((node.previousSibling == null) ||
                          (node.previousSibling._type == HTML_BR) ||
+                         isNoteNode(node.previousSibling) ||
                          (isParagraphNode(node.previousSibling)) ||
                          (getNodeText(node.previousSibling).match(/\s$/)) ||
                          isItemNumber(node.previousSibling) ||
@@ -450,6 +457,7 @@
             if (isWhitespaceString(followingText)) {
                 return (havePrevChar &&
                         ((node.nextSibling == null) ||
+                         isNoteNode(node.nextSibling) ||
                          (followingText.length > 0) ||
                          (spacesUntilNextContent(node) != 0)));
             }
@@ -476,6 +484,15 @@
             var prevType = (prevNode != null) ? prevNode._type : 0;
             var nextType = (nextNode != null) ? nextNode._type : 0;
 
+            var prevIsNote = (prevNode != null) && isNoteNode(prevNode);
+            var nextIsNote = (nextNode != null) && isNoteNode(nextNode);
+            if (((nextNode == null) || !nodeHasContent(nextNode)) && prevIsNote)
+                return true;
+            if (((prevNode == null) || !nodeHasContent(prevNode)) && nextIsNote)
+                return true;
+            if (prevIsNote && nextIsNote)
+                return true;
+
             if ((prevNode == null) && (nextNode == null) &&
                 (CONTAINERS_ALLOWING_CHILDREN[type] ||
                 (isInlineNode(node) && !isOpaqueNode(node) && (type != HTML_BR))))
@@ -676,6 +693,47 @@
                  height: rect.height };
     }
 
+    function zeroWidthMidRect(rect)
+    {
+        var mid = rect.left + rect.width/2;
+        return { left: mid,
+                 right: mid, // 0 width
+                 top: rect.top,
+                 bottom: rect.bottom,
+                 width: 0,
+                 height: rect.height };
+    }
+
+    Position_noteAncestor = function(pos)
+    {
+        var node = Position_closestActualNode(pos);
+        for (; node != null; node = node.parentNode) {
+            if (isNoteNode(node))
+                return node;
+        }
+        return null;
+    }
+
+    Position_captionAncestor = function(pos)
+    {
+        var node = Position_closestActualNode(pos);
+        for (; node != null; node = node.parentNode) {
+            if ((node._type == HTML_FIGCAPTION) || (node._type == HTML_CAPTION))
+                return node;
+        }
+        return null;
+    }
+
+    Position_figureOrTableAncestor = function(pos)
+    {
+        var node = Position_closestActualNode(pos);
+        for (; node != null; node = node.parentNode) {
+            if ((node._type == HTML_FIGURE) || (node._type == HTML_TABLE))
+                return node;
+        }
+        return null;
+    }
+
     function exactRectAtPos(pos)
     {
         var node = pos.node;
@@ -733,12 +791,55 @@
         }
     }
 
+    function tempSpaceRect(parentNode,nextSibling)
+    {
+        var space = DOM_createTextNode(document,String.fromCharCode(160));
+        DOM_insertBefore(parentNode,space,nextSibling);
+        var range = new Range(space,0,space,1);
+        var rects = Range_getClientRects(range);
+        DOM_deleteNode(space);
+        if (rects.length > 0)
+            return rects[0];
+        else
+            return nil;
+    }
+
     Position_displayRectAtPos = function(pos)
     {
         rect = exactRectAtPos(pos);
         if (rect != null)
             return rect;
 
+        var noteNode = Position_noteAncestor(pos);
+        if ((noteNode != null) && !nodeHasContent(noteNode)) // In empty footnote or endnote
+            return zeroWidthMidRect(noteNode.getBoundingClientRect());
+
+        // If we're immediately before or after a footnote or endnote, calculate the rect by
+        // temporarily inserting a space character, and getting the rect at the start of that.
+        // This avoids us instead getting a rect inside the note, which is what would otherwise
+        // happen if there was no adjacent text node outside the note.
+        if ((pos.node.nodeType == Node.ELEMENT_NODE)) {
+            var before = pos.node.childNodes[pos.offset-1];
+            var after = pos.node.childNodes[pos.offset];
+            if (((before != null) && isNoteNode(before)) ||
+                ((after != null) && isNoteNode(after))) {
+                var rect = tempSpaceRect(pos.node,pos.node.childNodes[pos.offset]);
+                if (rect != null)
+                    return zeroWidthLeftRect(rect);
+            }
+        }
+
+        var captionNode = Position_captionAncestor(pos);
+        if ((captionNode != null) && !nodeHasContent(captionNode)) {
+            // Even if an empty caption has generated content (e.g. "Figure X: ") preceding it,
+            // we can't directly get the rect of that generated content. So we temporarily insert
+            // a text node containing a single space character, get the position to the right of
+            // that character, and then remove the text node.
+            var rect = tempSpaceRect(captionNode,null);
+            if (rect != null)
+                return zeroWidthRightRect(rect);
+        }
+
         var paragraph = Text_findParagraphBoundaries(pos);
 
         var backRect = null;
@@ -896,16 +997,30 @@
     // intended if the document's last text node is a direct child of the body (as it may be in some
     // HTML documents that users open).
 
+    function posOutsideSelection(pos)
+    {
+        pos = Position_preferElementPosition(pos);
+
+        if (!isSelectionSpan(pos.node))
+            return pos;
+
+        if (pos.offset == 0)
+            return new Position(pos.node.parentNode,DOM_nodeOffset(pos.node));
+        else if (pos.offset == pos.node.childNodes.length)
+            return new Position(pos.node.parentNode,DOM_nodeOffset(pos.node)+1);
+        else
+            return pos;
+    }
+
     Position_atPoint = function(x,y)
     {
         // In general, we can use document.caretRangeFromPoint(x,y) to determine the location of the
         // cursor based on screen coordinates. However, this doesn't work if the screen coordinates
         // are outside the bounding box of the document's body. So when this is true, we find either
         // the first or last non-whitespace text node, calculate a y value that is half-way between
-        // the top and bottom of its first or last rect (respectively), and then make a call to
-        // caretRangeFromPoint with the same x value but this new y value. This results in the
-        // cursor being placed on the first or last line when the user taps outside the document
-        // bounds.
+        // the top and bottom of its first or last rect (respectively), and use that instead. This
+        // results in the cursor being placed on the first or last line when the user taps outside
+        // the document bounds.
 
         var bodyRect = document.body.getBoundingClientRect();
         var boundaryRect = null;
@@ -914,12 +1029,8 @@
         else if (y >= bodyRect.bottom)
             boundaryRect = findLastTextRect();
 
-        if (boundaryRect != null) {
-            var boundaryY = boundaryRect.top + boundaryRect.height/2;
-            var range = document.caretRangeFromPoint(x,boundaryY);
-            if (range != null)
-                return new Position(range.startContainer,range.startOffset);
-        }
+        if (boundaryRect != null)
+            y = boundaryRect.top + boundaryRect.height/2;
 
         // We get here if the coordinates are inside the document's bounding rect, or if getting the
         // position from the first or last rect failed for some reason.
@@ -929,16 +1040,35 @@
             return null;
 
         var pos = new Position(range.startContainer,range.startOffset);
+        pos = Position_preferElementPosition(pos);
 
         if (pos.node.nodeType == Node.ELEMENT_NODE) {
-            var prev = pos.node.childNodes[pos.offset-1];
-            var next = pos.node.childNodes[pos.offset];
+            var outside = posOutsideSelection(pos);
+            var prev = outside.node.childNodes[outside.offset-1];
+            var next = outside.node.childNodes[outside.offset];
 
-            if ((prev != null) && (prev._type == HTML_IMG) && elementContainsPoint(prev,x,y))
+            if ((prev != null) && nodeMayContainPos(prev) && elementContainsPoint(prev,x,y))
                 return new Position(prev,0);
 
-            if ((next != null) && (next._type == HTML_IMG) && elementContainsPoint(next,x,y))
+            if ((next != null) && nodeMayContainPos(next) && elementContainsPoint(next,x,y))
                 return new Position(next,0);
+
+            if (next != null) {
+                var nextNode = outside.node;
+                var nextOffset = outside.offset+1;
+
+                if (isSelectionSpan(next) && (next.firstChild != null)) {
+                    nextNode = next;
+                    nextOffset = 1;
+                    next = next.firstChild;
+                }
+
+                if ((next != null) && isEmptyNoteNode(next)) {
+                    var rect = next.getBoundingClientRect();
+                    if (x > rect.right)
+                        return new Position(nextNode,nextOffset);
+                }
+            }
         }
 
         pos = adjustPositionForFigure(pos);
@@ -946,6 +1076,13 @@
         return pos;
     }
 
+    // This is used for nodes that can potentially be the right match for a hit test, but for
+    // which caretRangeFromPoint() returns the wrong result
+    function nodeMayContainPos(node)
+    {
+        return ((node._type == HTML_IMG) || isEmptyNoteNode(node));
+    }
+
     function elementContainsPoint(element,x,y)
     {
         var rect = element.getBoundingClientRect();
diff --git a/Editor/src/PostponedActions.js b/Editor/src/PostponedActions.js
index b63923f..d445536 100644
--- a/Editor/src/PostponedActions.js
+++ b/Editor/src/PostponedActions.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var PostponedActions_add;
 var PostponedActions_perform;
diff --git a/Editor/src/Preview.js b/Editor/src/Preview.js
index 9267b3f..97f9bf1 100644
--- a/Editor/src/Preview.js
+++ b/Editor/src/Preview.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Preview_showForStyle;
 
diff --git a/Editor/src/Range.js b/Editor/src/Range.js
index 883bbdc..8d7c655 100644
--- a/Editor/src/Range.js
+++ b/Editor/src/Range.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Range;
 
diff --git a/Editor/src/Scan.js b/Editor/src/Scan.js
index 88938a6..e6cf4f5 100644
--- a/Editor/src/Scan.js
+++ b/Editor/src/Scan.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Scan_reset;
 var Scan_next;
diff --git a/Editor/src/Selection.js b/Editor/src/Selection.js
index 42158f3..c4f8efb 100644
--- a/Editor/src/Selection.js
+++ b/Editor/src/Selection.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 // FIXME: cursor does not display correctly if it is after a space at the end of the line
 
@@ -316,6 +319,13 @@
                     newHighlights.push(wrapped);
                 }
             }
+            else if (isNoteNode(node)) {
+                if (!isSelectionHighlight(node.parentNode)) {
+                    var wrapped = DOM_wrapNode(node,"SPAN");
+                    DOM_setAttribute(wrapped,"class",Keys.SELECTION_CLASS);
+                    newHighlights.push(wrapped);
+                }
+            }
             else if (node.nodeType == Node.TEXT_NODE) {
                 createTextHighlight(node,data,newHighlights);
             }
diff --git a/Editor/src/StringBuilder.js b/Editor/src/StringBuilder.js
index 9c7460c..9332b79 100644
--- a/Editor/src/StringBuilder.js
+++ b/Editor/src/StringBuilder.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function StringBuilder()
 {
diff --git a/Editor/src/Styles.js b/Editor/src/Styles.js
index 232f3b0..c09f41d 100644
--- a/Editor/src/Styles.js
+++ b/Editor/src/Styles.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Styles_getRule;
 var Styles_nextSelectorAfter;
diff --git a/Editor/src/Tables.js b/Editor/src/Tables.js
index 153212c..f1f27be 100644
--- a/Editor/src/Tables.js
+++ b/Editor/src/Tables.js
@@ -1,22 +1,25 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Tables_insertTable;
 var Tables_addAdjacentRow;
 var Tables_addAdjacentColumn;
-var Tables_deleteOneRow;
-var Tables_deleteOneColumn;
+var Tables_removeAdjacentRow;
+var Tables_removeAdjacentColumn;
 var Tables_deleteRegion;
 var Tables_clearCells;
 var Tables_mergeCells;
@@ -278,19 +281,84 @@
         }
     }
 
+    function tableAtRightOfRange(range)
+    {
+        if (!Range_isEmpty(range))
+            return null;
+
+        var pos = Position_preferElementPosition(range.start);
+        if ((pos.node.nodeType == Node.ELEMENT_NODE) &&
+            (pos.offset < pos.node.childNodes.length) &&
+            (pos.node.childNodes[pos.offset]._type == HTML_TABLE)) {
+            var element = pos.node.childNodes[pos.offset];
+            var table = Tables_analyseStructure(element);
+            return table;
+        }
+        return null;
+    }
+
+    function tableAtLeftOfRange(range)
+    {
+        if (!Range_isEmpty(range))
+            return null;
+
+        var pos = Position_preferElementPosition(range.start);
+        if ((pos.node.nodeType == Node.ELEMENT_NODE) &&
+            (pos.offset > 0) &&
+            (pos.node.childNodes[pos.offset-1]._type == HTML_TABLE)) {
+            var element = pos.node.childNodes[pos.offset-1];
+            var table = Tables_analyseStructure(element);
+            return table;
+        }
+        return null;
+    }
+
+    function insertRowAbove(table,row)
+    {
+        var cell = Table_get(table,row,0);
+        var oldTR = cell.element.parentNode;
+        var newTR = DOM_createElement(document,"TR");
+        DOM_insertBefore(oldTR.parentNode,newTR,oldTR);
+        populateNewRow(table,newTR,row-1,row);
+    }
+
+    function insertRowBelow(table,row)
+    {
+        var cell = Table_get(table,row,0);
+        var oldTR = cell.element.parentNode;
+        var newTR = DOM_createElement(document,"TR");
+        DOM_insertBefore(oldTR.parentNode,newTR,oldTR.nextSibling);
+        populateNewRow(table,newTR,row+1,row);
+    }
+
+    function insertRowAdjacentToRange(range)
+    {
+        var table;
+
+        table = tableAtLeftOfRange(range);
+        if (table != null) {
+            insertRowBelow(table,table.numRows-1);
+            return;
+        }
+
+        table = tableAtRightOfRange(range);
+        if (table != null) {
+            insertRowAbove(table,0);
+            return;
+        }
+    }
+
     // public
     Tables_addAdjacentRow = function()
     {
         UndoManager_newGroup("Insert row below");
         Selection_preserveWhileExecuting(function() {
-            var region = Tables_regionFromRange(Selection_get(),true);
-            if (region != null) {
-                var cell = Table_get(region.structure,region.bottom,region.left);
-                var oldTR = cell.element.parentNode;
-                var newTR = DOM_createElement(document,"TR");
-                DOM_insertBefore(oldTR.parentNode,newTR,oldTR.nextSibling);
-                populateNewRow(region.structure,newTR,region.bottom+1,region.bottom);
-            }
+            var range = Selection_get();
+            var region = Tables_regionFromRange(range,true);
+            if (region != null)
+                insertRowBelow(region.structure,region.bottom);
+            else
+                insertRowAdjacentToRange(range);
         });
         UndoManager_newGroup();
     }
@@ -457,16 +525,41 @@
         }
     }
 
+    function insertColumnAdjacentToRange(range)
+    {
+        var table;
+
+        table = tableAtLeftOfRange(range);
+        if (table != null) {
+            var right = table.numCols-1;
+            addColElement(table,right,right+1);
+            addColumnCells(table,right,true);
+            return;
+        }
+
+        table = tableAtRightOfRange(range);
+        if (table != null) {
+            var left = 0;
+            addColElement(table,left,left-1);
+            addColumnCells(table,left,false);
+            return;
+        }
+    }
+
     // public
     Tables_addAdjacentColumn = function()
     {
         UndoManager_newGroup("Insert column at right");
         Selection_preserveWhileExecuting(function() {
-            var region = Tables_regionFromRange(Selection_get(),true);
+            var range = Selection_get();
+            var region = Tables_regionFromRange(range,true);
             if (region != null) {
                 addColElement(region.structure,region.right,region.right+1);
                 addColumnCells(region.structure,region.right,true);
             }
+            else {
+                insertColumnAdjacentToRange(range);
+            }
         });
         UndoManager_newGroup();
     }
@@ -529,10 +622,39 @@
         return row;
     }
 
-    Tables_deleteOneRow = function()
+    function removeRowAdjacentToRange(range)
     {
-        var region = Tables_regionFromRange(Selection_get(),true);
-        if ((region == null) || (region.structure.numRows <= 1))
+        var table;
+
+        table = tableAtLeftOfRange(range);
+        if ((table != null) && (table.numRows >= 2)) {
+            UndoManager_newGroup("Delete one row");
+            var row = table.numRows-1;
+            Tables_deleteRegion(new TableRegion(table,row,row,0,table.numCols-1));
+            UndoManager_newGroup();
+            return;
+        }
+
+        table = tableAtRightOfRange(range);
+        if ((table != null) && (table.numRows >= 2)) {
+            UndoManager_newGroup("Delete one row");
+            Tables_deleteRegion(new TableRegion(table,0,0,0,table.numCols-1));
+            UndoManager_newGroup();
+            return;
+        }
+    }
+
+    Tables_removeAdjacentRow = function()
+    {
+        var range = Selection_get();
+        var region = Tables_regionFromRange(range,true);
+
+        if (region == null) {
+            removeRowAdjacentToRange(range);
+            return;
+        }
+
+        if (region.structure.numRows <= 1)
             return;
 
         UndoManager_newGroup("Delete one row");
@@ -585,10 +707,39 @@
         UndoManager_newGroup();
     }
 
-    Tables_deleteOneColumn = function()
+    function removeColumnAdjacentToRange(range)
     {
-        var region = Tables_regionFromRange(Selection_get(),true);
-        if ((region == null) || (region.structure.numCols <= 1))
+        var table;
+
+        table = tableAtLeftOfRange(range);
+        if ((table != null) && (table.numCols >= 2)) {
+            UndoManager_newGroup("Delete one column");
+            var col = table.numCols-1;
+            Tables_deleteRegion(new TableRegion(table,0,table.numRows-1,col,col));
+            UndoManager_newGroup();
+            return;
+        }
+
+        table = tableAtRightOfRange(range);
+        if ((table != null) && (table.numCols >= 2)) {
+            UndoManager_newGroup("Delete one column");
+            Tables_deleteRegion(new TableRegion(table,0,table.numRows-1,0,0));
+            UndoManager_newGroup();
+            return;
+        }
+    }
+
+    Tables_removeAdjacentColumn = function()
+    {
+        var range = Selection_get();
+        var region = Tables_regionFromRange(range,true);
+
+        if (region == null) {
+            removeColumnAdjacentToRange(range);
+            return;
+        }
+
+        if (region.structure.numCols <= 1)
             return;
 
         UndoManager_newGroup("Delete one column");
diff --git a/Editor/src/Text.js b/Editor/src/Text.js
index 10a90b8..5a69feb 100644
--- a/Editor/src/Text.js
+++ b/Editor/src/Text.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Text_findParagraphBoundaries;
 var Text_analyseParagraph;
diff --git a/Editor/src/UndoManager.js b/Editor/src/UndoManager.js
index 44cb279..9f63c43 100644
--- a/Editor/src/UndoManager.js
+++ b/Editor/src/UndoManager.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 // FIXME: place a limit on the number of undo steps recorded - say, 30-50?
 
@@ -29,7 +32,6 @@
 var UndoManager_clear;
 var UndoManager_setProperty;
 var UndoManager_deleteProperty;
-var UndoManager_groupType;
 
 (function() {
 
@@ -263,14 +265,6 @@
         delete obj[name];
     }
 
-    UndoManager_groupType = function()
-    {
-        if (undoStack.length == 0)
-            return null;
-        else
-            return undoStack[undoStack.length-1].type;
-    }
-
 })();
 
 window.undoSupported = true;
diff --git a/Editor/src/Viewport.js b/Editor/src/Viewport.js
index c78df45..47fbdfd 100644
--- a/Editor/src/Viewport.js
+++ b/Editor/src/Viewport.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var Viewport_init;
 var Viewport_setViewportWidth;
diff --git a/Editor/src/first.js b/Editor/src/first.js
index 953ef4b..48cfd85 100644
--- a/Editor/src/first.js
+++ b/Editor/src/first.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 // FIXME: The _PREFIX variables below must be replaced with functions that return the
 // appropriate namespace prefix for the document in question (since we can't rely on the
diff --git a/Editor/src/traversal.js b/Editor/src/traversal.js
index 40227ea..439870f 100644
--- a/Editor/src/traversal.js
+++ b/Editor/src/traversal.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function prevNode(node)
 {
diff --git a/Editor/src/types.js b/Editor/src/types.js
index 243f5e9..b49a709 100644
--- a/Editor/src/types.js
+++ b/Editor/src/types.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var CONTAINER_ELEMENTS = new Array(HTML_COUNT);
 CONTAINER_ELEMENTS[HTML_DOCUMENT] = true;
@@ -135,6 +138,11 @@
     return BLOCK_ELEMENTS[node._type];
 }
 
+function isBlockOrNoteNode(node)
+{
+    return BLOCK_ELEMENTS[node._type] || isNoteNode(node);
+}
+
 function isInlineNode(node)
 {
     return INLINE_ELEMENTS[node._type];
@@ -164,6 +172,19 @@
             node.getAttribute("href").charAt(0) == "#");
 }
 
+function isNoteNode(node)
+{
+    if (node._type != HTML_SPAN)
+        return false;
+    var className = DOM_getAttribute(node,"class");
+    return ((className == "footnote") || (className == "endnote"));
+}
+
+function isEmptyNoteNode(node)
+{
+    return isNoteNode(node) && !nodeHasContent(node);
+}
+
 function isItemNumber(node)
 {
     if (node.nodeType == Node.TEXT_NODE) {
diff --git a/Editor/src/util.js b/Editor/src/util.js
index fbe23e4..191fc55 100644
--- a/Editor/src/util.js
+++ b/Editor/src/util.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function arrayContains(array,value)
 {
diff --git a/Editor/tests/PrettyPrinter.js b/Editor/tests/PrettyPrinter.js
index c39e7e1..f18d7ba 100644
--- a/Editor/tests/PrettyPrinter.js
+++ b/Editor/tests/PrettyPrinter.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 (function() {
 
@@ -157,6 +160,28 @@
         }
     }
 
+    function isContainer(node)
+    {
+        switch (node._type) {
+        case HTML_BODY:
+        case HTML_SECTION:
+        case HTML_FIGURE:
+        case HTML_TABLE:
+        case HTML_TBODY:
+        case HTML_THEAD:
+        case HTML_TFOOT:
+        case HTML_TR:
+        case HTML_DIV:
+        case HTML_UL:
+        case HTML_OL:
+        case HTML_NAV:
+        case HTML_COLGROUP:
+            return true;
+        default:
+            return false;
+        }
+    }
+
     function prettyPrint(output,options,node,indent)
     {
         if ((node.nodeType == Node.ELEMENT_NODE) && (node.nodeName != "SCRIPT")) {
@@ -171,7 +196,7 @@
                         prettyPrint(output,options,child,"");
                     output.push(indent + "</" + name + ">\n");
                 }
-                else if (!options.separateLines && singleDescendents(node)) {
+                else if (!options.separateLines && singleDescendents(node) && !isContainer(node)) {
                     output.push(indent);
                     prettyPrintOneLine(output,options,node);
                     output.push("\n");
diff --git a/Editor/tests/autocorrect/AutoCorrectTests.js b/Editor/tests/autocorrect/AutoCorrectTests.js
index ba514bb..fdc771d 100644
--- a/Editor/tests/autocorrect/AutoCorrectTests.js
+++ b/Editor/tests/autocorrect/AutoCorrectTests.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function findTextMatching(re)
 {
diff --git a/Editor/tests/autocorrect/acceptCorrection-undo-expected.html b/Editor/tests/autocorrect/acceptCorrection-undo-expected.html
index 0460b60..3399e01 100644
--- a/Editor/tests/autocorrect/acceptCorrection-undo-expected.html
+++ b/Editor/tests/autocorrect/acceptCorrection-undo-expected.html
@@ -33,7 +33,9 @@
       </p>
     </body>
     ==================== Version 3 ====================
-    <body><p>one two three four five six seven[]</p></body>
+    <body>
+      <p>one two three four five six seven[]</p>
+    </body>
     ===================================================
     First undo to version 2: OK
     First undo to version 1: OK
diff --git a/Editor/tests/autocorrect/acceptCorrection02-expected.html b/Editor/tests/autocorrect/acceptCorrection02-expected.html
index 5848dfc..2257b03 100644
--- a/Editor/tests/autocorrect/acceptCorrection02-expected.html
+++ b/Editor/tests/autocorrect/acceptCorrection02-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head>
   </head>
-  <body><p>one two three four five[]</p></body>
+  <body>
+    <p>one two three four five[]</p>
+  </body>
 </html>
 
 Corrections:
diff --git a/Editor/tests/autocorrect/removedSpan02-expected.html b/Editor/tests/autocorrect/removedSpan02-expected.html
index 17b33b8..1815348 100644
--- a/Editor/tests/autocorrect/removedSpan02-expected.html
+++ b/Editor/tests/autocorrect/removedSpan02-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>th[]</p></body>
+  <body>
+    <p>th[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/autocorrect/removedSpan03-expected.html b/Editor/tests/autocorrect/removedSpan03-expected.html
index 7bf269f..b0c230d 100644
--- a/Editor/tests/autocorrect/removedSpan03-expected.html
+++ b/Editor/tests/autocorrect/removedSpan03-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>thex[]</p></body>
+  <body>
+    <p>thex[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/autocorrect/replaceCorrection-undo-expected.html b/Editor/tests/autocorrect/replaceCorrection-undo-expected.html
index e397207..badefe7 100644
--- a/Editor/tests/autocorrect/replaceCorrection-undo-expected.html
+++ b/Editor/tests/autocorrect/replaceCorrection-undo-expected.html
@@ -33,7 +33,9 @@
       </p>
     </body>
     ==================== Version 3 ====================
-    <body><p>one r3 three r2 five r1 seven[]</p></body>
+    <body>
+      <p>one r3 three r2 five r1 seven[]</p>
+    </body>
     ===================================================
     First undo to version 2: OK
     First undo to version 1: OK
diff --git a/Editor/tests/autocorrect/replaceCorrection02-expected.html b/Editor/tests/autocorrect/replaceCorrection02-expected.html
index 32f3134..659ad6f 100644
--- a/Editor/tests/autocorrect/replaceCorrection02-expected.html
+++ b/Editor/tests/autocorrect/replaceCorrection02-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head>
   </head>
-  <body><p>one B three A five[]</p></body>
+  <body>
+    <p>one B three A five[]</p>
+  </body>
 </html>
 
 Corrections:
diff --git a/Editor/tests/autocorrect/undo03-expected.html b/Editor/tests/autocorrect/undo03-expected.html
index 6900e6d..0280119 100644
--- a/Editor/tests/autocorrect/undo03-expected.html
+++ b/Editor/tests/autocorrect/undo03-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head>
   </head>
-  <body><p>one twox[]</p></body>
+  <body>
+    <p>one twox[]</p>
+  </body>
 </html>
 
 Corrections:
diff --git a/Editor/tests/clipboard/cut-li04-expected.html b/Editor/tests/clipboard/cut-li04-expected.html
index 9c6c5e3..edbaeae 100644
--- a/Editor/tests/clipboard/cut-li04-expected.html
+++ b/Editor/tests/clipboard/cut-li04-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body></body>
+  <body>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li05-expected.html b/Editor/tests/clipboard/cut-li05-expected.html
index 9c6c5e3..edbaeae 100644
--- a/Editor/tests/clipboard/cut-li05-expected.html
+++ b/Editor/tests/clipboard/cut-li05-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body></body>
+  <body>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li06-expected.html b/Editor/tests/clipboard/cut-li06-expected.html
index b51592c..53a2ebc 100644
--- a/Editor/tests/clipboard/cut-li06-expected.html
+++ b/Editor/tests/clipboard/cut-li06-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body></body>
+  <body>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li07-expected.html b/Editor/tests/clipboard/cut-li07-expected.html
index a8b01fb..84e2750 100644
--- a/Editor/tests/clipboard/cut-li07-expected.html
+++ b/Editor/tests/clipboard/cut-li07-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body></body>
+  <body>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li08-expected.html b/Editor/tests/clipboard/cut-li08-expected.html
index 0aa8552..62a7e5e 100644
--- a/Editor/tests/clipboard/cut-li08-expected.html
+++ b/Editor/tests/clipboard/cut-li08-expected.html
@@ -1,6 +1,10 @@
 <html>
   <head></head>
-  <body><ul><li>Zero</li></ul></body>
+  <body>
+    <ul>
+      <li>Zero</li>
+    </ul>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li09-expected.html b/Editor/tests/clipboard/cut-li09-expected.html
index 4ab8993..954bcf6 100644
--- a/Editor/tests/clipboard/cut-li09-expected.html
+++ b/Editor/tests/clipboard/cut-li09-expected.html
@@ -1,6 +1,10 @@
 <html>
   <head></head>
-  <body><ul><li>Four</li></ul></body>
+  <body>
+    <ul>
+      <li>Four</li>
+    </ul>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li11-expected.html b/Editor/tests/clipboard/cut-li11-expected.html
index 4092b56..389188e 100644
--- a/Editor/tests/clipboard/cut-li11-expected.html
+++ b/Editor/tests/clipboard/cut-li11-expected.html
@@ -1,6 +1,10 @@
 <html>
   <head></head>
-  <body><ul><li/></ul></body>
+  <body>
+    <ul>
+      <li/>
+    </ul>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li12-expected.html b/Editor/tests/clipboard/cut-li12-expected.html
index 4092b56..389188e 100644
--- a/Editor/tests/clipboard/cut-li12-expected.html
+++ b/Editor/tests/clipboard/cut-li12-expected.html
@@ -1,6 +1,10 @@
 <html>
   <head></head>
-  <body><ul><li/></ul></body>
+  <body>
+    <ul>
+      <li/>
+    </ul>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li15-expected.html b/Editor/tests/clipboard/cut-li15-expected.html
index 833d862..246eac6 100644
--- a/Editor/tests/clipboard/cut-li15-expected.html
+++ b/Editor/tests/clipboard/cut-li15-expected.html
@@ -1,6 +1,10 @@
 <html>
   <head></head>
-  <body><ul><li>One[]</li></ul></body>
+  <body>
+    <ul>
+      <li>One[]</li>
+    </ul>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li15a-expected.html b/Editor/tests/clipboard/cut-li15a-expected.html
index e7b87a1..dff4fb6 100644
--- a/Editor/tests/clipboard/cut-li15a-expected.html
+++ b/Editor/tests/clipboard/cut-li15a-expected.html
@@ -1,6 +1,10 @@
 <html>
   <head></head>
-  <body><ul><li><p>One[]</p></li></ul></body>
+  <body>
+    <ul>
+      <li><p>One[]</p></li>
+    </ul>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li16-expected.html b/Editor/tests/clipboard/cut-li16-expected.html
index 2737ea3..e030c62 100644
--- a/Editor/tests/clipboard/cut-li16-expected.html
+++ b/Editor/tests/clipboard/cut-li16-expected.html
@@ -1,6 +1,10 @@
 <html>
   <head></head>
-  <body><ul><li>[]Three</li></ul></body>
+  <body>
+    <ul>
+      <li>[]Three</li>
+    </ul>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/cut-li16a-expected.html b/Editor/tests/clipboard/cut-li16a-expected.html
index 98e3e0a..41619fc 100644
--- a/Editor/tests/clipboard/cut-li16a-expected.html
+++ b/Editor/tests/clipboard/cut-li16a-expected.html
@@ -1,6 +1,10 @@
 <html>
   <head></head>
-  <body><ul><li><p>[]Three</p></li></ul></body>
+  <body>
+    <ul>
+      <li><p>[]Three</p></li>
+    </ul>
+  </body>
 </html>
 
 text/html
diff --git a/Editor/tests/clipboard/paste-htmldoc01-expected.html b/Editor/tests/clipboard/paste-htmldoc01-expected.html
index d5446e7..49ad39a 100644
--- a/Editor/tests/clipboard/paste-htmldoc01-expected.html
+++ b/Editor/tests/clipboard/paste-htmldoc01-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div class="page" title="Page 1">[]</div></body>
+  <body>
+    <div class="page" title="Page 1">
+      []
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/clipboard/paste-htmldoc02-expected.html b/Editor/tests/clipboard/paste-htmldoc02-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/clipboard/paste-htmldoc02-expected.html
+++ b/Editor/tests/clipboard/paste-htmldoc02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/clipboard/paste-invalid10-expected.html b/Editor/tests/clipboard/paste-invalid10-expected.html
index d000049..bf06bed 100644
--- a/Editor/tests/clipboard/paste-invalid10-expected.html
+++ b/Editor/tests/clipboard/paste-invalid10-expected.html
@@ -2,7 +2,13 @@
   <head></head>
   <body>
     <p id="p1" z="1">Before</p>
-    <table><tbody><tr><td>Table[]</td></tr></tbody></table>
+    <table>
+      <tbody>
+        <tr>
+          <td>Table[]</td>
+        </tr>
+      </tbody>
+    </table>
     <p z="1">After</p>
   </body>
 </html>
diff --git a/Editor/tests/clipboard/paste01-expected.html b/Editor/tests/clipboard/paste01-expected.html
index 764f28f..b91c420 100644
--- a/Editor/tests/clipboard/paste01-expected.html
+++ b/Editor/tests/clipboard/paste01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text[]</p></body>
+  <body>
+    <p>Sample text[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/clipboard/paste02-expected.html b/Editor/tests/clipboard/paste02-expected.html
index 4d6f98e..f3ebde4 100644
--- a/Editor/tests/clipboard/paste02-expected.html
+++ b/Editor/tests/clipboard/paste02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>ASample text[]B</p></body>
+  <body>
+    <p>ASample text[]B</p>
+  </body>
 </html>
diff --git a/Editor/tests/clipboard/paste03-expected.html b/Editor/tests/clipboard/paste03-expected.html
index 764f28f..b91c420 100644
--- a/Editor/tests/clipboard/paste03-expected.html
+++ b/Editor/tests/clipboard/paste03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text[]</p></body>
+  <body>
+    <p>Sample text[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/clipboard/paste04-expected.html b/Editor/tests/clipboard/paste04-expected.html
index 4d6f98e..f3ebde4 100644
--- a/Editor/tests/clipboard/paste04-expected.html
+++ b/Editor/tests/clipboard/paste04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>ASample text[]B</p></body>
+  <body>
+    <p>ASample text[]B</p>
+  </body>
 </html>
diff --git a/Editor/tests/clipboard/pasteText-whitespace01-expected.html b/Editor/tests/clipboard/pasteText-whitespace01-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/clipboard/pasteText-whitespace01-expected.html
+++ b/Editor/tests/clipboard/pasteText-whitespace01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteBeforeParagraph-list01-expected.html b/Editor/tests/cursor/deleteBeforeParagraph-list01-expected.html
index 814e47d..6b29d99 100644
--- a/Editor/tests/cursor/deleteBeforeParagraph-list01-expected.html
+++ b/Editor/tests/cursor/deleteBeforeParagraph-list01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Heading[]List item</h1></body>
+  <body>
+    <h1>Heading[]List item</h1>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteBeforeParagraph-list01a-expected.html b/Editor/tests/cursor/deleteBeforeParagraph-list01a-expected.html
index 2212855..56b2016 100644
--- a/Editor/tests/cursor/deleteBeforeParagraph-list01a-expected.html
+++ b/Editor/tests/cursor/deleteBeforeParagraph-list01a-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Head[]item</h1></body>
+  <body>
+    <h1>Head[]item</h1>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteBeforeParagraph-list02a-expected.html b/Editor/tests/cursor/deleteBeforeParagraph-list02a-expected.html
index ab3ff63..cb02a93 100644
--- a/Editor/tests/cursor/deleteBeforeParagraph-list02a-expected.html
+++ b/Editor/tests/cursor/deleteBeforeParagraph-list02a-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Heading[]</h1></body>
+  <body>
+    <h1>Heading[]</h1>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteBeforeParagraph-list03a-expected.html b/Editor/tests/cursor/deleteBeforeParagraph-list03a-expected.html
index 4bac699..f71834a 100644
--- a/Editor/tests/cursor/deleteBeforeParagraph-list03a-expected.html
+++ b/Editor/tests/cursor/deleteBeforeParagraph-list03a-expected.html
@@ -2,6 +2,8 @@
   <head></head>
   <body>
     <h1>Head[]o</h1>
-    <ul><li><p>Three</p></li></ul>
+    <ul>
+      <li><p>Three</p></li>
+    </ul>
   </body>
 </html>
diff --git a/Editor/tests/cursor/deleteBeforeParagraph01-expected.html b/Editor/tests/cursor/deleteBeforeParagraph01-expected.html
index e7f6b51..a6d4d90 100644
--- a/Editor/tests/cursor/deleteBeforeParagraph01-expected.html
+++ b/Editor/tests/cursor/deleteBeforeParagraph01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Heading[]Paragraph</h1></body>
+  <body>
+    <h1>Heading[]Paragraph</h1>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteBeforeParagraph01a-expected.html b/Editor/tests/cursor/deleteBeforeParagraph01a-expected.html
index 1b1e421..ffab8d1 100644
--- a/Editor/tests/cursor/deleteBeforeParagraph01a-expected.html
+++ b/Editor/tests/cursor/deleteBeforeParagraph01a-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Head[]aph</h1></body>
+  <body>
+    <h1>Head[]aph</h1>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteBeforeParagraph02-expected.html b/Editor/tests/cursor/deleteBeforeParagraph02-expected.html
index e7f6b51..a6d4d90 100644
--- a/Editor/tests/cursor/deleteBeforeParagraph02-expected.html
+++ b/Editor/tests/cursor/deleteBeforeParagraph02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Heading[]Paragraph</h1></body>
+  <body>
+    <h1>Heading[]Paragraph</h1>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteBeforeParagraph02a-expected.html b/Editor/tests/cursor/deleteBeforeParagraph02a-expected.html
index 1b1e421..ffab8d1 100644
--- a/Editor/tests/cursor/deleteBeforeParagraph02a-expected.html
+++ b/Editor/tests/cursor/deleteBeforeParagraph02a-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Head[]aph</h1></body>
+  <body>
+    <h1>Head[]aph</h1>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-emoji02-expected.html b/Editor/tests/cursor/deleteCharacter-emoji02-expected.html
index 1132e2d..77c9d9f 100644
--- a/Editor/tests/cursor/deleteCharacter-emoji02-expected.html
+++ b/Editor/tests/cursor/deleteCharacter-emoji02-expected.html
@@ -3,5 +3,7 @@
     <meta charset="utf-8"/>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><p>😃👿[]</p></body>
+  <body>
+    <p>😃👿[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-emoji03-expected.html b/Editor/tests/cursor/deleteCharacter-emoji03-expected.html
index 46518c4..4969443 100644
--- a/Editor/tests/cursor/deleteCharacter-emoji03-expected.html
+++ b/Editor/tests/cursor/deleteCharacter-emoji03-expected.html
@@ -3,5 +3,7 @@
     <meta charset="utf-8"/>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><p>before[]</p></body>
+  <body>
+    <p>before[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-emoji04-expected.html b/Editor/tests/cursor/deleteCharacter-emoji04-expected.html
index 4f8962e..bca34fc 100644
--- a/Editor/tests/cursor/deleteCharacter-emoji04-expected.html
+++ b/Editor/tests/cursor/deleteCharacter-emoji04-expected.html
@@ -3,5 +3,7 @@
     <meta charset="utf-8"/>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><p>before😃👿[]</p></body>
+  <body>
+    <p>before😃👿[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-emoji05-expected.html b/Editor/tests/cursor/deleteCharacter-emoji05-expected.html
index a8f151a..6bc2dfc 100644
--- a/Editor/tests/cursor/deleteCharacter-emoji05-expected.html
+++ b/Editor/tests/cursor/deleteCharacter-emoji05-expected.html
@@ -3,5 +3,7 @@
     <meta charset="utf-8"/>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><p>[]after</p></body>
+  <body>
+    <p>[]after</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-emoji06-expected.html b/Editor/tests/cursor/deleteCharacter-emoji06-expected.html
index d9da288..be7725c 100644
--- a/Editor/tests/cursor/deleteCharacter-emoji06-expected.html
+++ b/Editor/tests/cursor/deleteCharacter-emoji06-expected.html
@@ -3,5 +3,7 @@
     <meta charset="utf-8"/>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><p>😃👿[]after</p></body>
+  <body>
+    <p>😃👿[]after</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-emoji07-expected.html b/Editor/tests/cursor/deleteCharacter-emoji07-expected.html
index 35e19b7..b830d5b 100644
--- a/Editor/tests/cursor/deleteCharacter-emoji07-expected.html
+++ b/Editor/tests/cursor/deleteCharacter-emoji07-expected.html
@@ -3,5 +3,7 @@
     <meta charset="utf-8"/>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><p>before[]after</p></body>
+  <body>
+    <p>before[]after</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-emoji08-expected.html b/Editor/tests/cursor/deleteCharacter-emoji08-expected.html
index 9824806..fd1ee55 100644
--- a/Editor/tests/cursor/deleteCharacter-emoji08-expected.html
+++ b/Editor/tests/cursor/deleteCharacter-emoji08-expected.html
@@ -3,5 +3,7 @@
     <meta charset="utf-8"/>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><p>before😃👿[]after</p></body>
+  <body>
+    <p>before😃👿[]after</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote01-expected.html b/Editor/tests/cursor/deleteCharacter-endnote01-expected.html
new file mode 100644
index 0000000..225c9b4
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote01-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      []after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote01-input.html b/Editor/tests/cursor/deleteCharacter-endnote01-input.html
new file mode 100644
index 0000000..0757734
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote01-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote">[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote02-expected.html b/Editor/tests/cursor/deleteCharacter-endnote02-expected.html
new file mode 100644
index 0000000..225c9b4
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote02-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      []after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote02-input.html b/Editor/tests/cursor/deleteCharacter-endnote02-input.html
new file mode 100644
index 0000000..b55d7d2
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote02-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote"><b>[]</b></span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote03-expected.html b/Editor/tests/cursor/deleteCharacter-endnote03-expected.html
new file mode 100644
index 0000000..895cd24
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote03-expected.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>before[]</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote03-input.html b/Editor/tests/cursor/deleteCharacter-endnote03-input.html
new file mode 100644
index 0000000..d94a572
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote03-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote">[]</span></p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote04-expected.html b/Editor/tests/cursor/deleteCharacter-endnote04-expected.html
new file mode 100644
index 0000000..88dd17b
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote04-expected.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote04-input.html b/Editor/tests/cursor/deleteCharacter-endnote04-input.html
new file mode 100644
index 0000000..f6ad6e1
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote04-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p><span class="endnote">[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote05-expected.html b/Editor/tests/cursor/deleteCharacter-endnote05-expected.html
new file mode 100644
index 0000000..0abd902
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote05-expected.html
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>Initial paragraph</p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote05-input.html b/Editor/tests/cursor/deleteCharacter-endnote05-input.html
new file mode 100644
index 0000000..0f82b31
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote05-input.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>Initial paragraph</p>
+  <p><span class="endnote">[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote06-expected.html b/Editor/tests/cursor/deleteCharacter-endnote06-expected.html
new file mode 100644
index 0000000..225c9b4
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote06-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      []after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote06-input.html b/Editor/tests/cursor/deleteCharacter-endnote06-input.html
new file mode 100644
index 0000000..bcaeeb1
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote06-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote"></span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote07-expected.html b/Editor/tests/cursor/deleteCharacter-endnote07-expected.html
new file mode 100644
index 0000000..225c9b4
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote07-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      []after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote07-input.html b/Editor/tests/cursor/deleteCharacter-endnote07-input.html
new file mode 100644
index 0000000..efd68bc
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote07-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote"><b></b></span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote08-expected.html b/Editor/tests/cursor/deleteCharacter-endnote08-expected.html
new file mode 100644
index 0000000..e2952bf
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote08-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      []
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote08-input.html b/Editor/tests/cursor/deleteCharacter-endnote08-input.html
new file mode 100644
index 0000000..bff2f51
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote08-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote"></span>[]</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote09-expected.html b/Editor/tests/cursor/deleteCharacter-endnote09-expected.html
new file mode 100644
index 0000000..88dd17b
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote09-expected.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote09-input.html b/Editor/tests/cursor/deleteCharacter-endnote09-input.html
new file mode 100644
index 0000000..ab3f8ac
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote09-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p><span class="endnote"></span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote10-expected.html b/Editor/tests/cursor/deleteCharacter-endnote10-expected.html
new file mode 100644
index 0000000..0abd902
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote10-expected.html
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>Initial paragraph</p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-endnote10-input.html b/Editor/tests/cursor/deleteCharacter-endnote10-input.html
new file mode 100644
index 0000000..8f7aa92
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-endnote10-input.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>Initial paragraph</p>
+  <p><span class="endnote"></span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-figcaption03-expected.html b/Editor/tests/cursor/deleteCharacter-figcaption03-expected.html
new file mode 100644
index 0000000..f1ab352
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-figcaption03-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
+    []
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-figcaption03-input.html b/Editor/tests/cursor/deleteCharacter-figcaption03-input.html
new file mode 100644
index 0000000..0b9dced
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-figcaption03-input.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <figure>
+    <img src="../figures/nothing.png">
+    <figcaption>[]</figcaption>
+  </figure>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-figcaption04-expected.html b/Editor/tests/cursor/deleteCharacter-figcaption04-expected.html
new file mode 100644
index 0000000..f1ab352
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-figcaption04-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
+    []
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-figcaption04-input.html b/Editor/tests/cursor/deleteCharacter-figcaption04-input.html
new file mode 100644
index 0000000..9aa4617
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-figcaption04-input.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <figure>
+    <img src="../figures/nothing.png">
+    <figcaption><b>[]</b></figcaption>
+  </figure>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote01-expected.html b/Editor/tests/cursor/deleteCharacter-footnote01-expected.html
new file mode 100644
index 0000000..225c9b4
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote01-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      []after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote01-input.html b/Editor/tests/cursor/deleteCharacter-footnote01-input.html
new file mode 100644
index 0000000..cf02a9e
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote01-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote02-expected.html b/Editor/tests/cursor/deleteCharacter-footnote02-expected.html
new file mode 100644
index 0000000..225c9b4
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote02-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      []after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote02-input.html b/Editor/tests/cursor/deleteCharacter-footnote02-input.html
new file mode 100644
index 0000000..495be1c
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote02-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote"><b>[]</b></span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote03-expected.html b/Editor/tests/cursor/deleteCharacter-footnote03-expected.html
new file mode 100644
index 0000000..895cd24
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote03-expected.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>before[]</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote03-input.html b/Editor/tests/cursor/deleteCharacter-footnote03-input.html
new file mode 100644
index 0000000..6ecd381
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote03-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">[]</span></p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote04-expected.html b/Editor/tests/cursor/deleteCharacter-footnote04-expected.html
new file mode 100644
index 0000000..88dd17b
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote04-expected.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote04-input.html b/Editor/tests/cursor/deleteCharacter-footnote04-input.html
new file mode 100644
index 0000000..c84d178
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote04-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p><span class="footnote">[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote05-expected.html b/Editor/tests/cursor/deleteCharacter-footnote05-expected.html
new file mode 100644
index 0000000..0abd902
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote05-expected.html
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>Initial paragraph</p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote05-input.html b/Editor/tests/cursor/deleteCharacter-footnote05-input.html
new file mode 100644
index 0000000..5f7eb34
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote05-input.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>Initial paragraph</p>
+  <p><span class="footnote">[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote06-expected.html b/Editor/tests/cursor/deleteCharacter-footnote06-expected.html
new file mode 100644
index 0000000..225c9b4
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote06-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      []after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote06-input.html b/Editor/tests/cursor/deleteCharacter-footnote06-input.html
new file mode 100644
index 0000000..3496595
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote06-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote"></span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote07-expected.html b/Editor/tests/cursor/deleteCharacter-footnote07-expected.html
new file mode 100644
index 0000000..225c9b4
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote07-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      []after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote07-input.html b/Editor/tests/cursor/deleteCharacter-footnote07-input.html
new file mode 100644
index 0000000..141f5d8
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote07-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote"><b></b></span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote08-expected.html b/Editor/tests/cursor/deleteCharacter-footnote08-expected.html
new file mode 100644
index 0000000..e2952bf
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote08-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      []
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote08-input.html b/Editor/tests/cursor/deleteCharacter-footnote08-input.html
new file mode 100644
index 0000000..9b637e2
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote08-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote"></span>[]</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote09-expected.html b/Editor/tests/cursor/deleteCharacter-footnote09-expected.html
new file mode 100644
index 0000000..88dd17b
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote09-expected.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote09-input.html b/Editor/tests/cursor/deleteCharacter-footnote09-input.html
new file mode 100644
index 0000000..6f74db3
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote09-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p><span class="footnote"></span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote10-expected.html b/Editor/tests/cursor/deleteCharacter-footnote10-expected.html
new file mode 100644
index 0000000..0abd902
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote10-expected.html
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>Initial paragraph</p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-footnote10-input.html b/Editor/tests/cursor/deleteCharacter-footnote10-input.html
new file mode 100644
index 0000000..ad5a014
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-footnote10-input.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>Initial paragraph</p>
+  <p><span class="footnote"></span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-link02-expected.html b/Editor/tests/cursor/deleteCharacter-link02-expected.html
index 7fe0864..7b72d83 100644
--- a/Editor/tests/cursor/deleteCharacter-link02-expected.html
+++ b/Editor/tests/cursor/deleteCharacter-link02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Text[]</p></body>
+  <body>
+    <p>Text[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-list06-expected.html b/Editor/tests/cursor/deleteCharacter-list06-expected.html
index 8718df2..1e26a12 100644
--- a/Editor/tests/cursor/deleteCharacter-list06-expected.html
+++ b/Editor/tests/cursor/deleteCharacter-list06-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li>[]</li></ul></body>
+  <body>
+    <ul>
+      <li>[]</li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-list07-expected.html b/Editor/tests/cursor/deleteCharacter-list07-expected.html
index 764f28f..b91c420 100644
--- a/Editor/tests/cursor/deleteCharacter-list07-expected.html
+++ b/Editor/tests/cursor/deleteCharacter-list07-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text[]</p></body>
+  <body>
+    <p>Sample text[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter-tablecaption01-expected.html b/Editor/tests/cursor/deleteCharacter-tablecaption01-expected.html
new file mode 100644
index 0000000..02fd8e0
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-tablecaption01-expected.html
@@ -0,0 +1,18 @@
+<html>
+  <head></head>
+  <body>
+    <table width="100%">
+      <tbody>
+        <tr>
+          <td>One</td>
+          <td>Two</td>
+        </tr>
+        <tr>
+          <td>Three</td>
+          <td>Four</td>
+        </tr>
+      </tbody>
+    </table>
+    []
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-tablecaption01-input.html b/Editor/tests/cursor/deleteCharacter-tablecaption01-input.html
new file mode 100644
index 0000000..5089a5d
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-tablecaption01-input.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+<table width="100%">
+  <caption>[]</caption>
+  <tr>
+    <td>One</td>
+    <td>Two</td>
+  </tr>
+  <tr>
+    <td>Three</td>
+    <td>Four</td>
+  </tr>
+</table>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-tablecaption02-expected.html b/Editor/tests/cursor/deleteCharacter-tablecaption02-expected.html
new file mode 100644
index 0000000..02fd8e0
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-tablecaption02-expected.html
@@ -0,0 +1,18 @@
+<html>
+  <head></head>
+  <body>
+    <table width="100%">
+      <tbody>
+        <tr>
+          <td>One</td>
+          <td>Two</td>
+        </tr>
+        <tr>
+          <td>Three</td>
+          <td>Four</td>
+        </tr>
+      </tbody>
+    </table>
+    []
+  </body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter-tablecaption02-input.html b/Editor/tests/cursor/deleteCharacter-tablecaption02-input.html
new file mode 100644
index 0000000..402c13b
--- /dev/null
+++ b/Editor/tests/cursor/deleteCharacter-tablecaption02-input.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Cursor_deleteCharacter();
+    showSelection();
+}
+</script>
+</head>
+<body>
+<table width="100%">
+  <caption><b>[]</b></caption>
+  <tr>
+    <td>One</td>
+    <td>Two</td>
+  </tr>
+  <tr>
+    <td>Three</td>
+    <td>Four</td>
+  </tr>
+</table>
+</body>
+</html>
diff --git a/Editor/tests/cursor/deleteCharacter01-expected.html b/Editor/tests/cursor/deleteCharacter01-expected.html
index 94217ba..b8521ba 100644
--- a/Editor/tests/cursor/deleteCharacter01-expected.html
+++ b/Editor/tests/cursor/deleteCharacter01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample tex[]</p></body>
+  <body>
+    <p>Sample tex[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter02-expected.html b/Editor/tests/cursor/deleteCharacter02-expected.html
index cf06551..778bf58 100644
--- a/Editor/tests/cursor/deleteCharacter02-expected.html
+++ b/Editor/tests/cursor/deleteCharacter02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Samp[]e text</p></body>
+  <body>
+    <p>Samp[]e text</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter03-expected.html b/Editor/tests/cursor/deleteCharacter03-expected.html
index 973cbfe..2ad40ec 100644
--- a/Editor/tests/cursor/deleteCharacter03-expected.html
+++ b/Editor/tests/cursor/deleteCharacter03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>[]Sample text</p></body>
+  <body>
+    <p>[]Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter04-expected.html b/Editor/tests/cursor/deleteCharacter04-expected.html
index d70dc08..26501f0 100644
--- a/Editor/tests/cursor/deleteCharacter04-expected.html
+++ b/Editor/tests/cursor/deleteCharacter04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>First one[]Second two</p></body>
+  <body>
+    <p>First one[]Second two</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter04a-expected.html b/Editor/tests/cursor/deleteCharacter04a-expected.html
index d70dc08..26501f0 100644
--- a/Editor/tests/cursor/deleteCharacter04a-expected.html
+++ b/Editor/tests/cursor/deleteCharacter04a-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>First one[]Second two</p></body>
+  <body>
+    <p>First one[]Second two</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter04b-expected.html b/Editor/tests/cursor/deleteCharacter04b-expected.html
index d70dc08..26501f0 100644
--- a/Editor/tests/cursor/deleteCharacter04b-expected.html
+++ b/Editor/tests/cursor/deleteCharacter04b-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>First one[]Second two</p></body>
+  <body>
+    <p>First one[]Second two</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter05-expected.html b/Editor/tests/cursor/deleteCharacter05-expected.html
index d208d94..e72ef9e 100644
--- a/Editor/tests/cursor/deleteCharacter05-expected.html
+++ b/Editor/tests/cursor/deleteCharacter05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>First one[]Second two</b></p></body>
+  <body>
+    <p><b>First one[]Second two</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter05a-expected.html b/Editor/tests/cursor/deleteCharacter05a-expected.html
index d208d94..e72ef9e 100644
--- a/Editor/tests/cursor/deleteCharacter05a-expected.html
+++ b/Editor/tests/cursor/deleteCharacter05a-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>First one[]Second two</b></p></body>
+  <body>
+    <p><b>First one[]Second two</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter05b-expected.html b/Editor/tests/cursor/deleteCharacter05b-expected.html
index d208d94..e72ef9e 100644
--- a/Editor/tests/cursor/deleteCharacter05b-expected.html
+++ b/Editor/tests/cursor/deleteCharacter05b-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>First one[]Second two</b></p></body>
+  <body>
+    <p><b>First one[]Second two</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter06-expected.html b/Editor/tests/cursor/deleteCharacter06-expected.html
index d6e2b98..761f37c 100644
--- a/Editor/tests/cursor/deleteCharacter06-expected.html
+++ b/Editor/tests/cursor/deleteCharacter06-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p>First one[]Second two</p></div></body>
+  <body>
+    <div>
+      <p>First one[]Second two</p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter06a-expected.html b/Editor/tests/cursor/deleteCharacter06a-expected.html
index d6e2b98..761f37c 100644
--- a/Editor/tests/cursor/deleteCharacter06a-expected.html
+++ b/Editor/tests/cursor/deleteCharacter06a-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p>First one[]Second two</p></div></body>
+  <body>
+    <div>
+      <p>First one[]Second two</p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter06b-expected.html b/Editor/tests/cursor/deleteCharacter06b-expected.html
index d6e2b98..761f37c 100644
--- a/Editor/tests/cursor/deleteCharacter06b-expected.html
+++ b/Editor/tests/cursor/deleteCharacter06b-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p>First one[]Second two</p></div></body>
+  <body>
+    <div>
+      <p>First one[]Second two</p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter07-expected.html b/Editor/tests/cursor/deleteCharacter07-expected.html
index 68cd062..a853cc3 100644
--- a/Editor/tests/cursor/deleteCharacter07-expected.html
+++ b/Editor/tests/cursor/deleteCharacter07-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p><b>First one[]Second two</b></p></div></body>
+  <body>
+    <div>
+      <p><b>First one[]Second two</b></p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter07a-expected.html b/Editor/tests/cursor/deleteCharacter07a-expected.html
index 68cd062..a853cc3 100644
--- a/Editor/tests/cursor/deleteCharacter07a-expected.html
+++ b/Editor/tests/cursor/deleteCharacter07a-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p><b>First one[]Second two</b></p></div></body>
+  <body>
+    <div>
+      <p><b>First one[]Second two</b></p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter07b-expected.html b/Editor/tests/cursor/deleteCharacter07b-expected.html
index 68cd062..a853cc3 100644
--- a/Editor/tests/cursor/deleteCharacter07b-expected.html
+++ b/Editor/tests/cursor/deleteCharacter07b-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p><b>First one[]Second two</b></p></div></body>
+  <body>
+    <div>
+      <p><b>First one[]Second two</b></p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter11-expected.html b/Editor/tests/cursor/deleteCharacter11-expected.html
index 4d05c15..336000d 100644
--- a/Editor/tests/cursor/deleteCharacter11-expected.html
+++ b/Editor/tests/cursor/deleteCharacter11-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>xxxxxxx[]</p></body>
+  <body>
+    <p>xxxxxxx[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter12-expected.html b/Editor/tests/cursor/deleteCharacter12-expected.html
index d3c0179..4910ec8 100644
--- a/Editor/tests/cursor/deleteCharacter12-expected.html
+++ b/Editor/tests/cursor/deleteCharacter12-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>xxxxxx[]</p></body>
+  <body>
+    <p>xxxxxx[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter13-expected.html b/Editor/tests/cursor/deleteCharacter13-expected.html
index 68f4276..8637eec 100644
--- a/Editor/tests/cursor/deleteCharacter13-expected.html
+++ b/Editor/tests/cursor/deleteCharacter13-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>xxxx[]</p></body>
+  <body>
+    <p>xxxx[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter14-expected.html b/Editor/tests/cursor/deleteCharacter14-expected.html
index 159d25e..a4da091 100644
--- a/Editor/tests/cursor/deleteCharacter14-expected.html
+++ b/Editor/tests/cursor/deleteCharacter14-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>A []</p></body>
+  <body>
+    <p>A []</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter15-expected.html b/Editor/tests/cursor/deleteCharacter15-expected.html
index 2da444d..e65b76c 100644
--- a/Editor/tests/cursor/deleteCharacter15-expected.html
+++ b/Editor/tests/cursor/deleteCharacter15-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>A  []</p></body>
+  <body>
+    <p>A  []</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter16-expected.html b/Editor/tests/cursor/deleteCharacter16-expected.html
index 70a8bd2..882eb15 100644
--- a/Editor/tests/cursor/deleteCharacter16-expected.html
+++ b/Editor/tests/cursor/deleteCharacter16-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>A []</body>
+  <body>
+    A []
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter17-expected.html b/Editor/tests/cursor/deleteCharacter17-expected.html
index 74a208b..e98abd8 100644
--- a/Editor/tests/cursor/deleteCharacter17-expected.html
+++ b/Editor/tests/cursor/deleteCharacter17-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>A  []</body>
+  <body>
+    A  []
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter21-expected.html b/Editor/tests/cursor/deleteCharacter21-expected.html
index 8a2c526..ff21e33 100644
--- a/Editor/tests/cursor/deleteCharacter21-expected.html
+++ b/Editor/tests/cursor/deleteCharacter21-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p id="p2">[]Sample text</p></body>
+  <body>
+    <p id="p2">[]Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/deleteCharacter22-expected.html b/Editor/tests/cursor/deleteCharacter22-expected.html
index 2a939c0..768504b 100644
--- a/Editor/tests/cursor/deleteCharacter22-expected.html
+++ b/Editor/tests/cursor/deleteCharacter22-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1 id="item1">[]Sample text</h1></body>
+  <body>
+    <h1 id="item1">[]Sample text</h1>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/doubleSpacePeriod01-expected.html b/Editor/tests/cursor/doubleSpacePeriod01-expected.html
index a42b30a..69d4d64 100644
--- a/Editor/tests/cursor/doubleSpacePeriod01-expected.html
+++ b/Editor/tests/cursor/doubleSpacePeriod01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text.&nbsp;[]</p></body>
+  <body>
+    <p>Sample text.&nbsp;[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/doubleSpacePeriod02-expected.html b/Editor/tests/cursor/doubleSpacePeriod02-expected.html
index a42b30a..69d4d64 100644
--- a/Editor/tests/cursor/doubleSpacePeriod02-expected.html
+++ b/Editor/tests/cursor/doubleSpacePeriod02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text.&nbsp;[]</p></body>
+  <body>
+    <p>Sample text.&nbsp;[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/doubleSpacePeriod03-expected.html b/Editor/tests/cursor/doubleSpacePeriod03-expected.html
index a42b30a..69d4d64 100644
--- a/Editor/tests/cursor/doubleSpacePeriod03-expected.html
+++ b/Editor/tests/cursor/doubleSpacePeriod03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text.&nbsp;[]</p></body>
+  <body>
+    <p>Sample text.&nbsp;[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/doubleSpacePeriod04-expected.html b/Editor/tests/cursor/doubleSpacePeriod04-expected.html
index b629b7d..ecc4490 100644
--- a/Editor/tests/cursor/doubleSpacePeriod04-expected.html
+++ b/Editor/tests/cursor/doubleSpacePeriod04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text []</p></body>
+  <body>
+    <p>Sample text []</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/doubleSpacePeriod05-expected.html b/Editor/tests/cursor/doubleSpacePeriod05-expected.html
index ece68a9..c758a73 100644
--- a/Editor/tests/cursor/doubleSpacePeriod05-expected.html
+++ b/Editor/tests/cursor/doubleSpacePeriod05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text. A.&nbsp;[]</p></body>
+  <body>
+    <p>Sample text. A.&nbsp;[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/enter-delete01-expected.html b/Editor/tests/cursor/enter-delete01-expected.html
index 764f28f..b91c420 100644
--- a/Editor/tests/cursor/enter-delete01-expected.html
+++ b/Editor/tests/cursor/enter-delete01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text[]</p></body>
+  <body>
+    <p>Sample text[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/enter-delete02-expected.html b/Editor/tests/cursor/enter-delete02-expected.html
index 764f28f..b91c420 100644
--- a/Editor/tests/cursor/enter-delete02-expected.html
+++ b/Editor/tests/cursor/enter-delete02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text[]</p></body>
+  <body>
+    <p>Sample text[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/enter-delete03-expected.html b/Editor/tests/cursor/enter-delete03-expected.html
index 764f28f..b91c420 100644
--- a/Editor/tests/cursor/enter-delete03-expected.html
+++ b/Editor/tests/cursor/enter-delete03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text[]</p></body>
+  <body>
+    <p>Sample text[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/enterAfterFigure01-expected.html b/Editor/tests/cursor/enterAfterFigure01-expected.html
index a3c9f6c..1423796 100644
--- a/Editor/tests/cursor/enterAfterFigure01-expected.html
+++ b/Editor/tests/cursor/enterAfterFigure01-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
     <p>
       []
       <br/>
diff --git a/Editor/tests/cursor/enterAfterFigure02-expected.html b/Editor/tests/cursor/enterAfterFigure02-expected.html
index f2e19ab..e30e81e 100644
--- a/Editor/tests/cursor/enterAfterFigure02-expected.html
+++ b/Editor/tests/cursor/enterAfterFigure02-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
     <p>a</p>
     <p>
       []
diff --git a/Editor/tests/cursor/enterAfterFigure03-expected.html b/Editor/tests/cursor/enterAfterFigure03-expected.html
index acffee0..28082ef 100644
--- a/Editor/tests/cursor/enterAfterFigure03-expected.html
+++ b/Editor/tests/cursor/enterAfterFigure03-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
     <p>
       []
       <br/>
diff --git a/Editor/tests/cursor/enterBeforeFigure01-expected.html b/Editor/tests/cursor/enterBeforeFigure01-expected.html
index caad8da..6ca614d 100644
--- a/Editor/tests/cursor/enterBeforeFigure01-expected.html
+++ b/Editor/tests/cursor/enterBeforeFigure01-expected.html
@@ -6,6 +6,8 @@
       []
       <br/>
     </p>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
   </body>
 </html>
diff --git a/Editor/tests/cursor/enterBeforeFigure02-expected.html b/Editor/tests/cursor/enterBeforeFigure02-expected.html
index 303c756..9f4264f 100644
--- a/Editor/tests/cursor/enterBeforeFigure02-expected.html
+++ b/Editor/tests/cursor/enterBeforeFigure02-expected.html
@@ -7,6 +7,8 @@
       []
       <br/>
     </p>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
   </body>
 </html>
diff --git a/Editor/tests/cursor/enterBeforeFigure03-expected.html b/Editor/tests/cursor/enterBeforeFigure03-expected.html
index b24e06e..58cb2c2 100644
--- a/Editor/tests/cursor/enterBeforeFigure03-expected.html
+++ b/Editor/tests/cursor/enterBeforeFigure03-expected.html
@@ -4,6 +4,8 @@
     <p>one two three</p>
     <p><br/></p>
     <p>[]a</p>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
   </body>
 </html>
diff --git a/Editor/tests/cursor/enterPressed-emptyContainer03-expected.html b/Editor/tests/cursor/enterPressed-emptyContainer03-expected.html
index 8ce762c..46f41bb 100644
--- a/Editor/tests/cursor/enterPressed-emptyContainer03-expected.html
+++ b/Editor/tests/cursor/enterPressed-emptyContainer03-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <figure><figcaption></figcaption></figure>
+    <figure>
+      <figcaption></figcaption>
+    </figure>
     <p>
       []
       <br/>
diff --git a/Editor/tests/cursor/enterPressed-emptyContainer03a-expected.html b/Editor/tests/cursor/enterPressed-emptyContainer03a-expected.html
index 0b6036b..07efe23 100644
--- a/Editor/tests/cursor/enterPressed-emptyContainer03a-expected.html
+++ b/Editor/tests/cursor/enterPressed-emptyContainer03a-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <figure><figcaption/></figure>
+    <figure>
+      <figcaption/>
+    </figure>
     <p>
       []
       <br/>
diff --git a/Editor/tests/cursor/enterPressed-emptyContainer04-expected.html b/Editor/tests/cursor/enterPressed-emptyContainer04-expected.html
index f8ec74c..3b39650 100644
--- a/Editor/tests/cursor/enterPressed-emptyContainer04-expected.html
+++ b/Editor/tests/cursor/enterPressed-emptyContainer04-expected.html
@@ -3,7 +3,11 @@
   <body>
     <table>
       <caption></caption>
-      <tbody><tr><td>Cell</td></tr></tbody>
+      <tbody>
+        <tr>
+          <td>Cell</td>
+        </tr>
+      </tbody>
     </table>
     <p>
       []
diff --git a/Editor/tests/cursor/enterPressed-emptyContainer04a-expected.html b/Editor/tests/cursor/enterPressed-emptyContainer04a-expected.html
index ebdb3ca..020c65b 100644
--- a/Editor/tests/cursor/enterPressed-emptyContainer04a-expected.html
+++ b/Editor/tests/cursor/enterPressed-emptyContainer04a-expected.html
@@ -3,7 +3,11 @@
   <body>
     <table>
       <caption/>
-      <tbody><tr><td>Cell</td></tr></tbody>
+      <tbody>
+        <tr>
+          <td>Cell</td>
+        </tr>
+      </tbody>
     </table>
     <p>
       []
diff --git a/Editor/tests/cursor/enterPressed-endnote01-expected.html b/Editor/tests/cursor/enterPressed-endnote01-expected.html
new file mode 100644
index 0000000..a0c6787
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote01-expected.html
@@ -0,0 +1,13 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>before</p>
+    <p>
+      []
+      <span class="endnote"/>
+      after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote01-input.html b/Editor/tests/cursor/enterPressed-endnote01-input.html
new file mode 100644
index 0000000..6291f6e
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote01-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before[]<span class="endnote"></span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote02-expected.html b/Editor/tests/cursor/enterPressed-endnote02-expected.html
new file mode 100644
index 0000000..3c70c9e
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote02-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="endnote"></span>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote02-input.html b/Editor/tests/cursor/enterPressed-endnote02-input.html
new file mode 100644
index 0000000..0349f77
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote02-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote">[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote03-expected.html b/Editor/tests/cursor/enterPressed-endnote03-expected.html
new file mode 100644
index 0000000..a3966aa
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote03-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="endnote"/>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote03-input.html b/Editor/tests/cursor/enterPressed-endnote03-input.html
new file mode 100644
index 0000000..ab48008
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote03-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote"></span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote04-expected.html b/Editor/tests/cursor/enterPressed-endnote04-expected.html
new file mode 100644
index 0000000..1664fb5
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote04-expected.html
@@ -0,0 +1,13 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>before</p>
+    <p>
+      []
+      <span class="endnote">endnote</span>
+      after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote04-input.html b/Editor/tests/cursor/enterPressed-endnote04-input.html
new file mode 100644
index 0000000..e9e050e
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote04-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before[]<span class="endnote">endnote</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote05-expected.html b/Editor/tests/cursor/enterPressed-endnote05-expected.html
new file mode 100644
index 0000000..ad381c2
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote05-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="endnote">endnote</span>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote05-input.html b/Editor/tests/cursor/enterPressed-endnote05-input.html
new file mode 100644
index 0000000..6a3b67f
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote05-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote">[]endnote</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote06-expected.html b/Editor/tests/cursor/enterPressed-endnote06-expected.html
new file mode 100644
index 0000000..ad381c2
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote06-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="endnote">endnote</span>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote06-input.html b/Editor/tests/cursor/enterPressed-endnote06-input.html
new file mode 100644
index 0000000..f13892f
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote06-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote">end[]note</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote07-expected.html b/Editor/tests/cursor/enterPressed-endnote07-expected.html
new file mode 100644
index 0000000..ad381c2
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote07-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="endnote">endnote</span>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote07-input.html b/Editor/tests/cursor/enterPressed-endnote07-input.html
new file mode 100644
index 0000000..c57b762
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote07-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote">endnote[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote08-expected.html b/Editor/tests/cursor/enterPressed-endnote08-expected.html
new file mode 100644
index 0000000..ad381c2
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote08-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="endnote">endnote</span>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-endnote08-input.html b/Editor/tests/cursor/enterPressed-endnote08-input.html
new file mode 100644
index 0000000..79503c7
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-endnote08-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote">endnote</span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote01-expected.html b/Editor/tests/cursor/enterPressed-footnote01-expected.html
new file mode 100644
index 0000000..3650dc8
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote01-expected.html
@@ -0,0 +1,13 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>before</p>
+    <p>
+      []
+      <span class="footnote"/>
+      after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote01-input.html b/Editor/tests/cursor/enterPressed-footnote01-input.html
new file mode 100644
index 0000000..7d1d2a2
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote01-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before[]<span class="footnote"></span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote02-expected.html b/Editor/tests/cursor/enterPressed-footnote02-expected.html
new file mode 100644
index 0000000..5f52e4d
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote02-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="footnote"></span>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote02-input.html b/Editor/tests/cursor/enterPressed-footnote02-input.html
new file mode 100644
index 0000000..0ee7ad4
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote02-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote03-expected.html b/Editor/tests/cursor/enterPressed-footnote03-expected.html
new file mode 100644
index 0000000..b9ab906
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote03-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="footnote"/>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote03-input.html b/Editor/tests/cursor/enterPressed-footnote03-input.html
new file mode 100644
index 0000000..f2e61c0
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote03-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote"></span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote04-expected.html b/Editor/tests/cursor/enterPressed-footnote04-expected.html
new file mode 100644
index 0000000..31207ea
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote04-expected.html
@@ -0,0 +1,13 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>before</p>
+    <p>
+      []
+      <span class="footnote">footnote</span>
+      after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote04-input.html b/Editor/tests/cursor/enterPressed-footnote04-input.html
new file mode 100644
index 0000000..1c23e5e
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote04-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before[]<span class="footnote">footnote</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote05-expected.html b/Editor/tests/cursor/enterPressed-footnote05-expected.html
new file mode 100644
index 0000000..62280e9
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote05-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="footnote">footnote</span>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote05-input.html b/Editor/tests/cursor/enterPressed-footnote05-input.html
new file mode 100644
index 0000000..78dc232
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote05-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">[]footnote</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote06-expected.html b/Editor/tests/cursor/enterPressed-footnote06-expected.html
new file mode 100644
index 0000000..62280e9
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote06-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="footnote">footnote</span>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote06-input.html b/Editor/tests/cursor/enterPressed-footnote06-input.html
new file mode 100644
index 0000000..c7d159c
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote06-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">foot[]note</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote07-expected.html b/Editor/tests/cursor/enterPressed-footnote07-expected.html
new file mode 100644
index 0000000..62280e9
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote07-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="footnote">footnote</span>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote07-input.html b/Editor/tests/cursor/enterPressed-footnote07-input.html
new file mode 100644
index 0000000..e6777ad
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote07-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">footnote[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote08-expected.html b/Editor/tests/cursor/enterPressed-footnote08-expected.html
new file mode 100644
index 0000000..62280e9
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote08-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <p>
+      before
+      <span class="footnote">footnote</span>
+    </p>
+    <p>[]after</p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-footnote08-input.html b/Editor/tests/cursor/enterPressed-footnote08-input.html
new file mode 100644
index 0000000..50f1986
--- /dev/null
+++ b/Editor/tests/cursor/enterPressed-footnote08-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Cursor_enterPressed();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">footnote</span>[]after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/enterPressed-heading10-expected.html b/Editor/tests/cursor/enterPressed-heading10-expected.html
index 7e0351e..59cde39 100644
--- a/Editor/tests/cursor/enterPressed-heading10-expected.html
+++ b/Editor/tests/cursor/enterPressed-heading10-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1 id="item1">[]Some text</h1></body>
+  <body>
+    <h1 id="item1">[]Some text</h1>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/enterPressed-list31-expected.html b/Editor/tests/cursor/enterPressed-list31-expected.html
index 6a8264a..71813d4 100644
--- a/Editor/tests/cursor/enterPressed-list31-expected.html
+++ b/Editor/tests/cursor/enterPressed-list31-expected.html
@@ -8,7 +8,9 @@
           []
           <br/>
         </p>
-        <ul><li><p>Two</p></li></ul>
+        <ul>
+          <li><p>Two</p></li>
+        </ul>
       </li>
     </ul>
   </body>
diff --git a/Editor/tests/cursor/enterPressed-list32-expected.html b/Editor/tests/cursor/enterPressed-list32-expected.html
index 8d27a97..866a621 100644
--- a/Editor/tests/cursor/enterPressed-list32-expected.html
+++ b/Editor/tests/cursor/enterPressed-list32-expected.html
@@ -11,7 +11,9 @@
               []
               <br/>
             </p>
-            <ul><li><p>Three</p></li></ul>
+            <ul>
+              <li><p>Three</p></li>
+            </ul>
           </li>
         </ul>
       </li>
diff --git a/Editor/tests/cursor/enterPressed-list33-expected.html b/Editor/tests/cursor/enterPressed-list33-expected.html
index 6755de5..11d2874 100644
--- a/Editor/tests/cursor/enterPressed-list33-expected.html
+++ b/Editor/tests/cursor/enterPressed-list33-expected.html
@@ -11,7 +11,9 @@
         <ul>
           <li>
             <p>Two</p>
-            <ul><li><p>Three</p></li></ul>
+            <ul>
+              <li><p>Three</p></li>
+            </ul>
           </li>
         </ul>
       </li>
diff --git a/Editor/tests/cursor/enterPressed03-expected.html b/Editor/tests/cursor/enterPressed03-expected.html
index 8555b1f..ff5b01b 100644
--- a/Editor/tests/cursor/enterPressed03-expected.html
+++ b/Editor/tests/cursor/enterPressed03-expected.html
@@ -1,7 +1,11 @@
 <html>
   <head></head>
   <body>
-    <div>Sample t</div>
-    <div>[]ext</div>
+    <div>
+      Sample t
+    </div>
+    <div>
+      []ext
+    </div>
   </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty01-expected.html b/Editor/tests/cursor/insertCharacter-empty01-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty01-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty02-expected.html b/Editor/tests/cursor/insertCharacter-empty02-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty02-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty03-expected.html b/Editor/tests/cursor/insertCharacter-empty03-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty03-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty04-expected.html b/Editor/tests/cursor/insertCharacter-empty04-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty04-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty05-expected.html b/Editor/tests/cursor/insertCharacter-empty05-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty05-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty06-expected.html b/Editor/tests/cursor/insertCharacter-empty06-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty06-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty07-expected.html b/Editor/tests/cursor/insertCharacter-empty07-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty07-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty07-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty08-expected.html b/Editor/tests/cursor/insertCharacter-empty08-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty08-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty08-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty09-expected.html b/Editor/tests/cursor/insertCharacter-empty09-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty09-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty09-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty10-expected.html b/Editor/tests/cursor/insertCharacter-empty10-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty10-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty10-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-empty11-expected.html b/Editor/tests/cursor/insertCharacter-empty11-expected.html
index 809ffc3..cd37670 100644
--- a/Editor/tests/cursor/insertCharacter-empty11-expected.html
+++ b/Editor/tests/cursor/insertCharacter-empty11-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]</p></body>
+  <body>
+    <p>X[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-quotes01-expected.html b/Editor/tests/cursor/insertCharacter-quotes01-expected.html
index 1d54adb..c76e9d6 100644
--- a/Editor/tests/cursor/insertCharacter-quotes01-expected.html
+++ b/Editor/tests/cursor/insertCharacter-quotes01-expected.html
@@ -2,5 +2,7 @@
   <head>
     <meta charset="utf-8"/>
   </head>
-  <body><p>A 15" “screen”</p></body>
+  <body>
+    <p>A 15" “screen”</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-space01-expected.html b/Editor/tests/cursor/insertCharacter-space01-expected.html
index b1d8dad..17b4917 100644
--- a/Editor/tests/cursor/insertCharacter-space01-expected.html
+++ b/Editor/tests/cursor/insertCharacter-space01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X&nbsp;[]</p></body>
+  <body>
+    <p>X&nbsp;[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-spchar01-expected.html b/Editor/tests/cursor/insertCharacter-spchar01-expected.html
index 052e8a9..5be3b04 100644
--- a/Editor/tests/cursor/insertCharacter-spchar01-expected.html
+++ b/Editor/tests/cursor/insertCharacter-spchar01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>{X[]}</p></body>
+  <body>
+    <p>{X[]}</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-spchar03-expected.html b/Editor/tests/cursor/insertCharacter-spchar03-expected.html
index a9bb7f3..2877945 100644
--- a/Editor/tests/cursor/insertCharacter-spchar03-expected.html
+++ b/Editor/tests/cursor/insertCharacter-spchar03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>{X[]}</b></p></body>
+  <body>
+    <p><b>{X[]}</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-toparagraph01-expected.html b/Editor/tests/cursor/insertCharacter-toparagraph01-expected.html
index a64235d..92f8165 100644
--- a/Editor/tests/cursor/insertCharacter-toparagraph01-expected.html
+++ b/Editor/tests/cursor/insertCharacter-toparagraph01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]Sample text</p></body>
+  <body>
+    <p>X[]Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-toparagraph02-expected.html b/Editor/tests/cursor/insertCharacter-toparagraph02-expected.html
index fb4aefb..d287729 100644
--- a/Editor/tests/cursor/insertCharacter-toparagraph02-expected.html
+++ b/Editor/tests/cursor/insertCharacter-toparagraph02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample textX[]</p></body>
+  <body>
+    <p>Sample textX[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-toparagraph03-expected.html b/Editor/tests/cursor/insertCharacter-toparagraph03-expected.html
index a64235d..92f8165 100644
--- a/Editor/tests/cursor/insertCharacter-toparagraph03-expected.html
+++ b/Editor/tests/cursor/insertCharacter-toparagraph03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]Sample text</p></body>
+  <body>
+    <p>X[]Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-toparagraph04-expected.html b/Editor/tests/cursor/insertCharacter-toparagraph04-expected.html
index fb4aefb..d287729 100644
--- a/Editor/tests/cursor/insertCharacter-toparagraph04-expected.html
+++ b/Editor/tests/cursor/insertCharacter-toparagraph04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample textX[]</p></body>
+  <body>
+    <p>Sample textX[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-toparagraph05-expected.html b/Editor/tests/cursor/insertCharacter-toparagraph05-expected.html
index a64235d..92f8165 100644
--- a/Editor/tests/cursor/insertCharacter-toparagraph05-expected.html
+++ b/Editor/tests/cursor/insertCharacter-toparagraph05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]Sample text</p></body>
+  <body>
+    <p>X[]Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter-toparagraph06-expected.html b/Editor/tests/cursor/insertCharacter-toparagraph06-expected.html
index fb4aefb..d287729 100644
--- a/Editor/tests/cursor/insertCharacter-toparagraph06-expected.html
+++ b/Editor/tests/cursor/insertCharacter-toparagraph06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample textX[]</p></body>
+  <body>
+    <p>Sample textX[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter01-expected.html b/Editor/tests/cursor/insertCharacter01-expected.html
index fb4aefb..d287729 100644
--- a/Editor/tests/cursor/insertCharacter01-expected.html
+++ b/Editor/tests/cursor/insertCharacter01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample textX[]</p></body>
+  <body>
+    <p>Sample textX[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter02-expected.html b/Editor/tests/cursor/insertCharacter02-expected.html
index be6fe09..19a3a39 100644
--- a/Editor/tests/cursor/insertCharacter02-expected.html
+++ b/Editor/tests/cursor/insertCharacter02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample tX[]ext</p></body>
+  <body>
+    <p>Sample tX[]ext</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter03-expected.html b/Editor/tests/cursor/insertCharacter03-expected.html
index a64235d..92f8165 100644
--- a/Editor/tests/cursor/insertCharacter03-expected.html
+++ b/Editor/tests/cursor/insertCharacter03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]Sample text</p></body>
+  <body>
+    <p>X[]Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter04-expected.html b/Editor/tests/cursor/insertCharacter04-expected.html
index fb4aefb..d287729 100644
--- a/Editor/tests/cursor/insertCharacter04-expected.html
+++ b/Editor/tests/cursor/insertCharacter04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample textX[]</p></body>
+  <body>
+    <p>Sample textX[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter05-expected.html b/Editor/tests/cursor/insertCharacter05-expected.html
index be6fe09..19a3a39 100644
--- a/Editor/tests/cursor/insertCharacter05-expected.html
+++ b/Editor/tests/cursor/insertCharacter05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample tX[]ext</p></body>
+  <body>
+    <p>Sample tX[]ext</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter06-expected.html b/Editor/tests/cursor/insertCharacter06-expected.html
index a64235d..92f8165 100644
--- a/Editor/tests/cursor/insertCharacter06-expected.html
+++ b/Editor/tests/cursor/insertCharacter06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]Sample text</p></body>
+  <body>
+    <p>X[]Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter07-expected.html b/Editor/tests/cursor/insertCharacter07-expected.html
index a64235d..92f8165 100644
--- a/Editor/tests/cursor/insertCharacter07-expected.html
+++ b/Editor/tests/cursor/insertCharacter07-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>X[]Sample text</p></body>
+  <body>
+    <p>X[]Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter08-expected.html b/Editor/tests/cursor/insertCharacter08-expected.html
index fb4aefb..d287729 100644
--- a/Editor/tests/cursor/insertCharacter08-expected.html
+++ b/Editor/tests/cursor/insertCharacter08-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample textX[]</p></body>
+  <body>
+    <p>Sample textX[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertCharacter10-expected.html b/Editor/tests/cursor/insertCharacter10-expected.html
index 2f18009..475d789 100644
--- a/Editor/tests/cursor/insertCharacter10-expected.html
+++ b/Editor/tests/cursor/insertCharacter10-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text one two three[]</p></body>
+  <body>
+    <p>Sample text one two three[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertEndnote01-input.html b/Editor/tests/cursor/insertEndnote01-input.html
index 9ff5e4d..8a52b5c 100644
--- a/Editor/tests/cursor/insertEndnote01-input.html
+++ b/Editor/tests/cursor/insertEndnote01-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertEndnote("Endnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertEndnote02-input.html b/Editor/tests/cursor/insertEndnote02-input.html
index 1074b1c..0875055 100644
--- a/Editor/tests/cursor/insertEndnote02-input.html
+++ b/Editor/tests/cursor/insertEndnote02-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertEndnote("Endnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertEndnote03-input.html b/Editor/tests/cursor/insertEndnote03-input.html
index 9226476..b10fba6 100644
--- a/Editor/tests/cursor/insertEndnote03-input.html
+++ b/Editor/tests/cursor/insertEndnote03-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertEndnote("Endnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertEndnote04-expected.html b/Editor/tests/cursor/insertEndnote04-expected.html
index 2e542e9..dddacd5 100644
--- a/Editor/tests/cursor/insertEndnote04-expected.html
+++ b/Editor/tests/cursor/insertEndnote04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><span class="endnote">[Endnote content]</span></p></body>
+  <body>
+    <p><span class="endnote">[Endnote content]</span></p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertEndnote04-input.html b/Editor/tests/cursor/insertEndnote04-input.html
index 73cc7c4..5063da9 100644
--- a/Editor/tests/cursor/insertEndnote04-input.html
+++ b/Editor/tests/cursor/insertEndnote04-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertEndnote("Endnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertEndnote05-expected.html b/Editor/tests/cursor/insertEndnote05-expected.html
index 2e542e9..dddacd5 100644
--- a/Editor/tests/cursor/insertEndnote05-expected.html
+++ b/Editor/tests/cursor/insertEndnote05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><span class="endnote">[Endnote content]</span></p></body>
+  <body>
+    <p><span class="endnote">[Endnote content]</span></p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertEndnote05-input.html b/Editor/tests/cursor/insertEndnote05-input.html
index 04eac74..10e397f 100644
--- a/Editor/tests/cursor/insertEndnote05-input.html
+++ b/Editor/tests/cursor/insertEndnote05-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertEndnote("Endnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertEndnote06-expected.html b/Editor/tests/cursor/insertEndnote06-expected.html
index 2a32f60..47f40a9 100644
--- a/Editor/tests/cursor/insertEndnote06-expected.html
+++ b/Editor/tests/cursor/insertEndnote06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><span class="endnote">[Endnote content]</span></body>
+  <body>
+    <span class="endnote">[Endnote content]</span>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertEndnote06-input.html b/Editor/tests/cursor/insertEndnote06-input.html
index a527c5e..040d642 100644
--- a/Editor/tests/cursor/insertEndnote06-input.html
+++ b/Editor/tests/cursor/insertEndnote06-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertEndnote("Endnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertEndnote07-expected.html b/Editor/tests/cursor/insertEndnote07-expected.html
new file mode 100644
index 0000000..8b3f2f0
--- /dev/null
+++ b/Editor/tests/cursor/insertEndnote07-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      before
+      <span class="endnote">inside</span>
+      <span class="endnote">[Endnote content]</span>
+      after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/insertEndnote07-input.html b/Editor/tests/cursor/insertEndnote07-input.html
new file mode 100644
index 0000000..e4b618a
--- /dev/null
+++ b/Editor/tests/cursor/insertEndnote07-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Cursor_insertEndnote("Endnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before <span class="endnote">ins[]ide</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/insertEndnote08-expected.html b/Editor/tests/cursor/insertEndnote08-expected.html
new file mode 100644
index 0000000..8b3f2f0
--- /dev/null
+++ b/Editor/tests/cursor/insertEndnote08-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      before
+      <span class="endnote">inside</span>
+      <span class="endnote">[Endnote content]</span>
+      after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/insertEndnote08-input.html b/Editor/tests/cursor/insertEndnote08-input.html
new file mode 100644
index 0000000..5c5fa70
--- /dev/null
+++ b/Editor/tests/cursor/insertEndnote08-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Cursor_insertEndnote("Endnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before <span class="endnote">inside[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/insertEndnote09-expected.html b/Editor/tests/cursor/insertEndnote09-expected.html
new file mode 100644
index 0000000..8b3f2f0
--- /dev/null
+++ b/Editor/tests/cursor/insertEndnote09-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      before
+      <span class="endnote">inside</span>
+      <span class="endnote">[Endnote content]</span>
+      after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/insertEndnote09-input.html b/Editor/tests/cursor/insertEndnote09-input.html
new file mode 100644
index 0000000..d915ef5
--- /dev/null
+++ b/Editor/tests/cursor/insertEndnote09-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Cursor_insertEndnote("Endnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before <span class="endnote">[]inside</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/insertFootnote01-input.html b/Editor/tests/cursor/insertFootnote01-input.html
index 7d4852c..22c102b 100644
--- a/Editor/tests/cursor/insertFootnote01-input.html
+++ b/Editor/tests/cursor/insertFootnote01-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertFootnote("Footnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertFootnote02-input.html b/Editor/tests/cursor/insertFootnote02-input.html
index 0957ba4..e1ac92a 100644
--- a/Editor/tests/cursor/insertFootnote02-input.html
+++ b/Editor/tests/cursor/insertFootnote02-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertFootnote("Footnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertFootnote03-input.html b/Editor/tests/cursor/insertFootnote03-input.html
index ec62f58..b24f4df 100644
--- a/Editor/tests/cursor/insertFootnote03-input.html
+++ b/Editor/tests/cursor/insertFootnote03-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertFootnote("Footnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertFootnote04-expected.html b/Editor/tests/cursor/insertFootnote04-expected.html
index 48b50fb..331c33c 100644
--- a/Editor/tests/cursor/insertFootnote04-expected.html
+++ b/Editor/tests/cursor/insertFootnote04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><span class="footnote">[Footnote content]</span></p></body>
+  <body>
+    <p><span class="footnote">[Footnote content]</span></p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertFootnote04-input.html b/Editor/tests/cursor/insertFootnote04-input.html
index 22d9e2d..5e8ee78 100644
--- a/Editor/tests/cursor/insertFootnote04-input.html
+++ b/Editor/tests/cursor/insertFootnote04-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertFootnote("Footnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertFootnote05-expected.html b/Editor/tests/cursor/insertFootnote05-expected.html
index 48b50fb..331c33c 100644
--- a/Editor/tests/cursor/insertFootnote05-expected.html
+++ b/Editor/tests/cursor/insertFootnote05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><span class="footnote">[Footnote content]</span></p></body>
+  <body>
+    <p><span class="footnote">[Footnote content]</span></p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertFootnote05-input.html b/Editor/tests/cursor/insertFootnote05-input.html
index 5c3885e..a976635 100644
--- a/Editor/tests/cursor/insertFootnote05-input.html
+++ b/Editor/tests/cursor/insertFootnote05-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertFootnote("Footnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertFootnote06-expected.html b/Editor/tests/cursor/insertFootnote06-expected.html
index 86c4dac..a70222a 100644
--- a/Editor/tests/cursor/insertFootnote06-expected.html
+++ b/Editor/tests/cursor/insertFootnote06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><span class="footnote">[Footnote content]</span></body>
+  <body>
+    <span class="footnote">[Footnote content]</span>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/insertFootnote06-input.html b/Editor/tests/cursor/insertFootnote06-input.html
index 9452059..d4c318c 100644
--- a/Editor/tests/cursor/insertFootnote06-input.html
+++ b/Editor/tests/cursor/insertFootnote06-input.html
@@ -5,6 +5,7 @@
 function performTest()
 {
     Cursor_insertFootnote("Footnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
     showSelection();
 }
 </script>
diff --git a/Editor/tests/cursor/insertFootnote07-expected.html b/Editor/tests/cursor/insertFootnote07-expected.html
new file mode 100644
index 0000000..70fa0f7
--- /dev/null
+++ b/Editor/tests/cursor/insertFootnote07-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      before
+      <span class="footnote">inside</span>
+      <span class="footnote">[Footnote content]</span>
+      after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/insertFootnote07-input.html b/Editor/tests/cursor/insertFootnote07-input.html
new file mode 100644
index 0000000..98ed6d9
--- /dev/null
+++ b/Editor/tests/cursor/insertFootnote07-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Cursor_insertFootnote("Footnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before <span class="footnote">ins[]ide</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/insertFootnote08-expected.html b/Editor/tests/cursor/insertFootnote08-expected.html
new file mode 100644
index 0000000..70fa0f7
--- /dev/null
+++ b/Editor/tests/cursor/insertFootnote08-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      before
+      <span class="footnote">inside</span>
+      <span class="footnote">[Footnote content]</span>
+      after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/insertFootnote08-input.html b/Editor/tests/cursor/insertFootnote08-input.html
new file mode 100644
index 0000000..695c7d5
--- /dev/null
+++ b/Editor/tests/cursor/insertFootnote08-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Cursor_insertFootnote("Footnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before <span class="footnote">inside[]</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/insertFootnote09-expected.html b/Editor/tests/cursor/insertFootnote09-expected.html
new file mode 100644
index 0000000..70fa0f7
--- /dev/null
+++ b/Editor/tests/cursor/insertFootnote09-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      before
+      <span class="footnote">inside</span>
+      <span class="footnote">[Footnote content]</span>
+      after
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/cursor/insertFootnote09-input.html b/Editor/tests/cursor/insertFootnote09-input.html
new file mode 100644
index 0000000..9feec88
--- /dev/null
+++ b/Editor/tests/cursor/insertFootnote09-input.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Cursor_insertFootnote("Footnote content");
+    Selection_preserveWhileExecuting(showEmptyTextNodes);
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>before <span class="footnote">[]inside</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/cursor/nbsp01-expected.html b/Editor/tests/cursor/nbsp01-expected.html
index 0421d72..8098ad9 100644
--- a/Editor/tests/cursor/nbsp01-expected.html
+++ b/Editor/tests/cursor/nbsp01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text&nbsp;[]</p></body>
+  <body>
+    <p>Sample text&nbsp;[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/nbsp02-expected.html b/Editor/tests/cursor/nbsp02-expected.html
index b629b7d..ecc4490 100644
--- a/Editor/tests/cursor/nbsp02-expected.html
+++ b/Editor/tests/cursor/nbsp02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text []</p></body>
+  <body>
+    <p>Sample text []</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/nbsp03-expected.html b/Editor/tests/cursor/nbsp03-expected.html
index 8fcec03..61c2a8a 100644
--- a/Editor/tests/cursor/nbsp03-expected.html
+++ b/Editor/tests/cursor/nbsp03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text a[]</p></body>
+  <body>
+    <p>Sample text a[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/nbsp04-expected.html b/Editor/tests/cursor/nbsp04-expected.html
index 0421d72..8098ad9 100644
--- a/Editor/tests/cursor/nbsp04-expected.html
+++ b/Editor/tests/cursor/nbsp04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text&nbsp;[]</p></body>
+  <body>
+    <p>Sample text&nbsp;[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/nbsp05-expected.html b/Editor/tests/cursor/nbsp05-expected.html
index b629b7d..ecc4490 100644
--- a/Editor/tests/cursor/nbsp05-expected.html
+++ b/Editor/tests/cursor/nbsp05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text []</p></body>
+  <body>
+    <p>Sample text []</p>
+  </body>
 </html>
diff --git a/Editor/tests/cursor/textAfterFigure01-expected.html b/Editor/tests/cursor/textAfterFigure01-expected.html
index 19deea7..5498785 100644
--- a/Editor/tests/cursor/textAfterFigure01-expected.html
+++ b/Editor/tests/cursor/textAfterFigure01-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
     <p>X[]</p>
     <p>one two three</p>
   </body>
diff --git a/Editor/tests/cursor/textAfterFigure02-expected.html b/Editor/tests/cursor/textAfterFigure02-expected.html
index 47a6df3..5163f29 100644
--- a/Editor/tests/cursor/textAfterFigure02-expected.html
+++ b/Editor/tests/cursor/textAfterFigure02-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
     <p>aX[]</p>
     <p>one two three</p>
   </body>
diff --git a/Editor/tests/cursor/textAfterFigure03-expected.html b/Editor/tests/cursor/textAfterFigure03-expected.html
index 4da2c29..6035b43 100644
--- a/Editor/tests/cursor/textAfterFigure03-expected.html
+++ b/Editor/tests/cursor/textAfterFigure03-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
     <p>X[]a</p>
     <p>one two three</p>
   </body>
diff --git a/Editor/tests/cursor/textBeforeFigure01-expected.html b/Editor/tests/cursor/textBeforeFigure01-expected.html
index b264b98..99ccaa9 100644
--- a/Editor/tests/cursor/textBeforeFigure01-expected.html
+++ b/Editor/tests/cursor/textBeforeFigure01-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p>one two three</p>
     <p>X[]</p>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
   </body>
 </html>
diff --git a/Editor/tests/cursor/textBeforeFigure02-expected.html b/Editor/tests/cursor/textBeforeFigure02-expected.html
index 7fcff8f..92b6ebe 100644
--- a/Editor/tests/cursor/textBeforeFigure02-expected.html
+++ b/Editor/tests/cursor/textBeforeFigure02-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p>one two three</p>
     <p>aX[]</p>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
   </body>
 </html>
diff --git a/Editor/tests/cursor/textBeforeFigure03-expected.html b/Editor/tests/cursor/textBeforeFigure03-expected.html
index 8947896..37ef96c 100644
--- a/Editor/tests/cursor/textBeforeFigure03-expected.html
+++ b/Editor/tests/cursor/textBeforeFigure03-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p>one two three</p>
     <p>X[]a</p>
-    <figure><img src="../figures/nothing.png"/></figure>
+    <figure>
+      <img src="../figures/nothing.png"/>
+    </figure>
   </body>
 </html>
diff --git a/Editor/tests/dom/RangeTest.js b/Editor/tests/dom/RangeTest.js
index b182f63..2d69cc3 100644
--- a/Editor/tests/dom/RangeTest.js
+++ b/Editor/tests/dom/RangeTest.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var allPositions;
 var allPositionsIndexMap;
diff --git a/Editor/tests/dom/avoidInline01-expected.html b/Editor/tests/dom/avoidInline01-expected.html
index 85d14c3..9616757 100644
--- a/Editor/tests/dom/avoidInline01-expected.html
+++ b/Editor/tests/dom/avoidInline01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One</p></body>
+  <body>
+    <p>One</p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/ensureInlineNodesInParagraph01-expected.html b/Editor/tests/dom/ensureInlineNodesInParagraph01-expected.html
index 430934e..7bd9ea5 100644
--- a/Editor/tests/dom/ensureInlineNodesInParagraph01-expected.html
+++ b/Editor/tests/dom/ensureInlineNodesInParagraph01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Test</p></body>
+  <body>
+    <p>Test</p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/ensureValidHierarchy01-expected.html b/Editor/tests/dom/ensureValidHierarchy01-expected.html
index 9a38b37..d79a0f8 100644
--- a/Editor/tests/dom/ensureValidHierarchy01-expected.html
+++ b/Editor/tests/dom/ensureValidHierarchy01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>Sample text</b></p></body>
+  <body>
+    <p><b>Sample text</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/ensureValidHierarchy02-expected.html b/Editor/tests/dom/ensureValidHierarchy02-expected.html
index 9a38b37..d79a0f8 100644
--- a/Editor/tests/dom/ensureValidHierarchy02-expected.html
+++ b/Editor/tests/dom/ensureValidHierarchy02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>Sample text</b></p></body>
+  <body>
+    <p><b>Sample text</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/ensureValidHierarchy06-expected.html b/Editor/tests/dom/ensureValidHierarchy06-expected.html
index d26dd5b..300d365 100644
--- a/Editor/tests/dom/ensureValidHierarchy06-expected.html
+++ b/Editor/tests/dom/ensureValidHierarchy06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b><i><u>Sample text</u></i></b></p></body>
+  <body>
+    <p><b><i><u>Sample text</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/ensureValidHierarchy07-expected.html b/Editor/tests/dom/ensureValidHierarchy07-expected.html
index c9589ff..d1da84b 100644
--- a/Editor/tests/dom/ensureValidHierarchy07-expected.html
+++ b/Editor/tests/dom/ensureValidHierarchy07-expected.html
@@ -1,14 +1,22 @@
 <html>
   <head></head>
   <body>
-    <ul><li><b><i><u>Item 1</u></i></b></li></ul>
+    <ul>
+      <li><b><i><u>Item 1</u></i></b></li>
+    </ul>
     <b>
       <i>
         <u>
-          <ol><li>Item 2</li></ol>
+          <ol>
+            <li>Item 2</li>
+          </ol>
           <p>Sample text</p>
-          <ul><li>Item 3</li></ul>
-          <ol><li>Item 4</li></ol>
+          <ul>
+            <li>Item 3</li>
+          </ul>
+          <ol>
+            <li>Item 4</li>
+          </ol>
         </u>
       </i>
     </b>
diff --git a/Editor/tests/dom/ensureValidHierarchy08-expected.html b/Editor/tests/dom/ensureValidHierarchy08-expected.html
index d10f177..555f18d 100644
--- a/Editor/tests/dom/ensureValidHierarchy08-expected.html
+++ b/Editor/tests/dom/ensureValidHierarchy08-expected.html
@@ -2,13 +2,19 @@
   <head></head>
   <body>
     <b><i><u><ul><li>Item 1</li></ul></u></i></b>
-    <ol><li><b><i><u>Item 2</u></i></b></li></ol>
+    <ol>
+      <li><b><i><u>Item 2</u></i></b></li>
+    </ol>
     <b>
       <i>
         <u>
           <p>Sample text</p>
-          <ul><li>Item 3</li></ul>
-          <ol><li>Item 4</li></ol>
+          <ul>
+            <li>Item 3</li>
+          </ul>
+          <ol>
+            <li>Item 4</li>
+          </ol>
         </u>
       </i>
     </b>
diff --git a/Editor/tests/dom/ensureValidHierarchy09-expected.html b/Editor/tests/dom/ensureValidHierarchy09-expected.html
index 8d208ca..b463ceb 100644
--- a/Editor/tests/dom/ensureValidHierarchy09-expected.html
+++ b/Editor/tests/dom/ensureValidHierarchy09-expected.html
@@ -4,8 +4,12 @@
     <b>
       <i>
         <u>
-          <ul><li>Item 1</li></ul>
-          <ol><li>Item 2</li></ol>
+          <ul>
+            <li>Item 1</li>
+          </ul>
+          <ol>
+            <li>Item 2</li>
+          </ol>
         </u>
       </i>
     </b>
@@ -13,8 +17,12 @@
     <b>
       <i>
         <u>
-          <ul><li>Item 3</li></ul>
-          <ol><li>Item 4</li></ol>
+          <ul>
+            <li>Item 3</li>
+          </ul>
+          <ol>
+            <li>Item 4</li>
+          </ol>
         </u>
       </i>
     </b>
diff --git a/Editor/tests/dom/ensureValidHierarchy10-expected.html b/Editor/tests/dom/ensureValidHierarchy10-expected.html
index 3abc400..a77382d 100644
--- a/Editor/tests/dom/ensureValidHierarchy10-expected.html
+++ b/Editor/tests/dom/ensureValidHierarchy10-expected.html
@@ -4,13 +4,19 @@
     <b>
       <i>
         <u>
-          <ul><li>Item 1</li></ul>
-          <ol><li>Item 2</li></ol>
+          <ul>
+            <li>Item 1</li>
+          </ul>
+          <ol>
+            <li>Item 2</li>
+          </ol>
           <p>Sample text</p>
         </u>
       </i>
     </b>
-    <ul><li><b><i><u>Item 3</u></i></b></li></ul>
+    <ul>
+      <li><b><i><u>Item 3</u></i></b></li>
+    </ul>
     <b><i><u><ol><li>Item 4</li></ol></u></i></b>
   </body>
 </html>
diff --git a/Editor/tests/dom/ensureValidHierarchy11-expected.html b/Editor/tests/dom/ensureValidHierarchy11-expected.html
index 79abfad..1d96c09 100644
--- a/Editor/tests/dom/ensureValidHierarchy11-expected.html
+++ b/Editor/tests/dom/ensureValidHierarchy11-expected.html
@@ -4,13 +4,21 @@
     <b>
       <i>
         <u>
-          <ul><li>Item 1</li></ul>
-          <ol><li>Item 2</li></ol>
+          <ul>
+            <li>Item 1</li>
+          </ul>
+          <ol>
+            <li>Item 2</li>
+          </ol>
           <p>Sample text</p>
-          <ul><li>Item 3</li></ul>
+          <ul>
+            <li>Item 3</li>
+          </ul>
         </u>
       </i>
     </b>
-    <ol><li><b><i><u>Item 4</u></i></b></li></ol>
+    <ol>
+      <li><b><i><u>Item 4</u></i></b></li>
+    </ol>
   </body>
 </html>
diff --git a/Editor/tests/dom/mergeWithNeighbours01-expected.html b/Editor/tests/dom/mergeWithNeighbours01-expected.html
index 4a2e136..bb8d07e 100644
--- a/Editor/tests/dom/mergeWithNeighbours01-expected.html
+++ b/Editor/tests/dom/mergeWithNeighbours01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>OneT[woThreeFou]rFive</p></body>
+  <body>
+    <p>OneT[woThreeFou]rFive</p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/mergeWithNeighbours02-expected.html b/Editor/tests/dom/mergeWithNeighbours02-expected.html
index 375e220..e827e60 100644
--- a/Editor/tests/dom/mergeWithNeighbours02-expected.html
+++ b/Editor/tests/dom/mergeWithNeighbours02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>O[neTwoThreeFourFiv]e</p></body>
+  <body>
+    <p>O[neTwoThreeFourFiv]e</p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/mergeWithNeighbours03-expected.html b/Editor/tests/dom/mergeWithNeighbours03-expected.html
index 36e255d..9430e9d 100644
--- a/Editor/tests/dom/mergeWithNeighbours03-expected.html
+++ b/Editor/tests/dom/mergeWithNeighbours03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One[TwoThreeFourFive]</p></body>
+  <body>
+    <p>One[TwoThreeFourFive]</p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/mergeWithNeighbours04-expected.html b/Editor/tests/dom/mergeWithNeighbours04-expected.html
index 367f373..40431bb 100644
--- a/Editor/tests/dom/mergeWithNeighbours04-expected.html
+++ b/Editor/tests/dom/mergeWithNeighbours04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One[OneOneOneOne]</p></body>
+  <body>
+    <p>One[OneOneOneOne]</p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/mergeWithNeighbours05-expected.html b/Editor/tests/dom/mergeWithNeighbours05-expected.html
index 012fd26..1e895ad 100644
--- a/Editor/tests/dom/mergeWithNeighbours05-expected.html
+++ b/Editor/tests/dom/mergeWithNeighbours05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b><i>OneTwoThreeFour[FiveSixSevenEight]Nine</i></b></p></body>
+  <body>
+    <p><b><i>OneTwoThreeFour[FiveSixSevenEight]Nine</i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/mergeWithNeighbours07-expected.html b/Editor/tests/dom/mergeWithNeighbours07-expected.html
index 9e1999b..790e84c 100644
--- a/Editor/tests/dom/mergeWithNeighbours07-expected.html
+++ b/Editor/tests/dom/mergeWithNeighbours07-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>OneTwo[ThreeFour]Five</p></body>
+  <body>
+    <p>OneTwo[ThreeFour]Five</p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/mergeWithNeighbours11-expected.html b/Editor/tests/dom/mergeWithNeighbours11-expected.html
index b6a7057..73d9c83 100644
--- a/Editor/tests/dom/mergeWithNeighbours11-expected.html
+++ b/Editor/tests/dom/mergeWithNeighbours11-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b><i>OneTwoThree[FourFiveSix]SevenEightNine</i></b></p></body>
+  <body>
+    <p><b><i>OneTwoThree[FourFiveSix]SevenEightNine</i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/dom/replaceElement01-expected.html b/Editor/tests/dom/replaceElement01-expected.html
index a788a5c..bb9a23e 100644
--- a/Editor/tests/dom/replaceElement01-expected.html
+++ b/Editor/tests/dom/replaceElement01-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div>Sample text</div></body>
+  <body>
+    <div>
+      Sample text
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/dom/replaceElement02-expected.html b/Editor/tests/dom/replaceElement02-expected.html
index 2ba0efc..7b87b12 100644
--- a/Editor/tests/dom/replaceElement02-expected.html
+++ b/Editor/tests/dom/replaceElement02-expected.html
@@ -3,7 +3,9 @@
   <body>
     <p>One</p>
     <p>Two</p>
-    <div>Three</div>
+    <div>
+      Three
+    </div>
     <p>Four</p>
     <p>Five</p>
   </body>
diff --git a/Editor/tests/dom/replaceElement03-expected.html b/Editor/tests/dom/replaceElement03-expected.html
index d5a25eb..560309a 100644
--- a/Editor/tests/dom/replaceElement03-expected.html
+++ b/Editor/tests/dom/replaceElement03-expected.html
@@ -3,7 +3,9 @@
   <body>
     <p>One</p>
     <p>Two</p>
-    <div align="center" style="color: red">Three</div>
+    <div align="center" style="color: red">
+      Three
+    </div>
     <p>Four</p>
     <p>Five</p>
   </body>
diff --git a/Editor/tests/dom/replaceElement06-expected.html b/Editor/tests/dom/replaceElement06-expected.html
index 86ba135..362f32d 100644
--- a/Editor/tests/dom/replaceElement06-expected.html
+++ b/Editor/tests/dom/replaceElement06-expected.html
@@ -3,7 +3,9 @@
   <body>
     <p>One</p>
     <p>Two</p>
-    <div>Sam[ple te]xt</div>
+    <div>
+      Sam[ple te]xt
+    </div>
     <p>Six</p>
     <p>Seven</p>
   </body>
diff --git a/Editor/tests/dom/replaceElement07-expected.html b/Editor/tests/dom/replaceElement07-expected.html
index 13ec421..ef72dcb 100644
--- a/Editor/tests/dom/replaceElement07-expected.html
+++ b/Editor/tests/dom/replaceElement07-expected.html
@@ -4,7 +4,9 @@
     <p>One</p>
     <p>Two</p>
     [
-    <div>Sample text</div>
+    <div>
+      Sample text
+    </div>
     ]
     <p>Six</p>
     <p>Seven</p>
diff --git a/Editor/tests/dom/replaceElement08-expected.html b/Editor/tests/dom/replaceElement08-expected.html
index b4e915d..377cfda 100644
--- a/Editor/tests/dom/replaceElement08-expected.html
+++ b/Editor/tests/dom/replaceElement08-expected.html
@@ -3,7 +3,9 @@
   <body>
     <p>One</p>
     <p>Two</p>
-    <div>[Sample text]</div>
+    <div>
+      [Sample text]
+    </div>
     <p>Six</p>
     <p>Seven</p>
   </body>
diff --git a/Editor/tests/dom/splitAroundSelection-endnote01-expected.html b/Editor/tests/dom/splitAroundSelection-endnote01-expected.html
new file mode 100644
index 0000000..648d67e
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-endnote01-expected.html
@@ -0,0 +1,10 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="endnote">[two] three four</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-endnote01-input.html b/Editor/tests/dom/splitAroundSelection-endnote01-input.html
new file mode 100644
index 0000000..394273a
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-endnote01-input.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    var range = Selection_get();
+    Range_trackWhileExecuting(range,function() {
+        Formatting_splitAroundSelection(range);
+    });
+    showRangeAsBrackets(range);
+}
+</script>
+</head>
+<body>
+  <p>one <span class="endnote">[two] three four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-endnote02-expected.html b/Editor/tests/dom/splitAroundSelection-endnote02-expected.html
new file mode 100644
index 0000000..e722f31
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-endnote02-expected.html
@@ -0,0 +1,10 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="endnote">two [three] four</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-endnote02-input.html b/Editor/tests/dom/splitAroundSelection-endnote02-input.html
new file mode 100644
index 0000000..bf3250d
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-endnote02-input.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    var range = Selection_get();
+    Range_trackWhileExecuting(range,function() {
+        Formatting_splitAroundSelection(range);
+    });
+    showRangeAsBrackets(range);
+}
+</script>
+</head>
+<body>
+  <p>one <span class="endnote">two [three] four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-endnote03-expected.html b/Editor/tests/dom/splitAroundSelection-endnote03-expected.html
new file mode 100644
index 0000000..f3ac04e
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-endnote03-expected.html
@@ -0,0 +1,10 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="endnote">two three [four]</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-endnote03-input.html b/Editor/tests/dom/splitAroundSelection-endnote03-input.html
new file mode 100644
index 0000000..ed7cb29
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-endnote03-input.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    var range = Selection_get();
+    Range_trackWhileExecuting(range,function() {
+        Formatting_splitAroundSelection(range);
+    });
+    showRangeAsBrackets(range);
+}
+</script>
+</head>
+<body>
+  <p>one <span class="endnote">two three [four]</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-footnote01-expected.html b/Editor/tests/dom/splitAroundSelection-footnote01-expected.html
new file mode 100644
index 0000000..5245a0c
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-footnote01-expected.html
@@ -0,0 +1,10 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="footnote">[two] three four</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-footnote01-input.html b/Editor/tests/dom/splitAroundSelection-footnote01-input.html
new file mode 100644
index 0000000..256fdc7
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-footnote01-input.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    var range = Selection_get();
+    Range_trackWhileExecuting(range,function() {
+        Formatting_splitAroundSelection(range);
+    });
+    showRangeAsBrackets(range);
+}
+</script>
+</head>
+<body>
+  <p>one <span class="footnote">[two] three four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-footnote02-expected.html b/Editor/tests/dom/splitAroundSelection-footnote02-expected.html
new file mode 100644
index 0000000..fce0569
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-footnote02-expected.html
@@ -0,0 +1,10 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="footnote">two [three] four</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-footnote02-input.html b/Editor/tests/dom/splitAroundSelection-footnote02-input.html
new file mode 100644
index 0000000..737c18d
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-footnote02-input.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    var range = Selection_get();
+    Range_trackWhileExecuting(range,function() {
+        Formatting_splitAroundSelection(range);
+    });
+    showRangeAsBrackets(range);
+}
+</script>
+</head>
+<body>
+  <p>one <span class="footnote">two [three] four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-footnote03-expected.html b/Editor/tests/dom/splitAroundSelection-footnote03-expected.html
new file mode 100644
index 0000000..772d336
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-footnote03-expected.html
@@ -0,0 +1,10 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="footnote">two three [four]</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/dom/splitAroundSelection-footnote03-input.html b/Editor/tests/dom/splitAroundSelection-footnote03-input.html
new file mode 100644
index 0000000..7dd0542
--- /dev/null
+++ b/Editor/tests/dom/splitAroundSelection-footnote03-input.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    var range = Selection_get();
+    Range_trackWhileExecuting(range,function() {
+        Formatting_splitAroundSelection(range);
+    });
+    showRangeAsBrackets(range);
+}
+</script>
+</head>
+<body>
+  <p>one <span class="footnote">two three [four]</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/dom/tracking-delete01-expected.html b/Editor/tests/dom/tracking-delete01-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/dom/tracking-delete01-expected.html
+++ b/Editor/tests/dom/tracking-delete01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-delete02-expected.html b/Editor/tests/dom/tracking-delete02-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/dom/tracking-delete02-expected.html
+++ b/Editor/tests/dom/tracking-delete02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-delete03-expected.html b/Editor/tests/dom/tracking-delete03-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/dom/tracking-delete03-expected.html
+++ b/Editor/tests/dom/tracking-delete03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-mergeWithNeighbours01-expected.html b/Editor/tests/dom/tracking-mergeWithNeighbours01-expected.html
index d1477c0..b48aa59 100644
--- a/Editor/tests/dom/tracking-mergeWithNeighbours01-expected.html
+++ b/Editor/tests/dom/tracking-mergeWithNeighbours01-expected.html
@@ -1,7 +1,8 @@
 <html>
   <head>
   </head>
-  <body>-
+  <body>
+    -
 Before: positions[0] = (BODY,0)
 Before: positions[1] = (P,0)
 Before: positions[2] = (BR#br1,0)
@@ -51,5 +52,6 @@
 After: positions[21] = (BR#br2,0)
 After: positions[22] = (P,3) - changed from (P,5)
 After: positions[23] = (BODY,1)
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-mergeWithNeighbours02-expected.html b/Editor/tests/dom/tracking-mergeWithNeighbours02-expected.html
index 9a91f0d..9f592e5 100644
--- a/Editor/tests/dom/tracking-mergeWithNeighbours02-expected.html
+++ b/Editor/tests/dom/tracking-mergeWithNeighbours02-expected.html
@@ -1,7 +1,8 @@
 <html>
   <head>
   </head>
-  <body>-
+  <body>
+    -
 Before: positions[0] = (BODY,0)
 Before: positions[1] = (P,0)
 Before: positions[2] = (SPAN#span1,0)
@@ -65,5 +66,6 @@
 After: positions[28] = (SPAN#span5,0)
 After: positions[29] = (P,3) - changed from (P,5)
 After: positions[30] = (BODY,1)
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-moveNode-expected.html b/Editor/tests/dom/tracking-moveNode-expected.html
index 796ef0a..561690d 100644
--- a/Editor/tests/dom/tracking-moveNode-expected.html
+++ b/Editor/tests/dom/tracking-moveNode-expected.html
@@ -1,7 +1,8 @@
 <html>
   <head>
   </head>
-  <body>-
+  <body>
+    -
 Before: positions[0] = (BODY,0)
 Before: positions[1] = (P#p1,0)
 Before: positions[2] = (B,0)
@@ -173,5 +174,6 @@
 After: positions[82] = (B,2)
 After: positions[83] = (P#p2,6) - changed from (P#p2,5)
 After: positions[84] = (BODY,2)
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-removeNodeButKeepChildren-expected.html b/Editor/tests/dom/tracking-removeNodeButKeepChildren-expected.html
index 88f6503..95eab37 100644
--- a/Editor/tests/dom/tracking-removeNodeButKeepChildren-expected.html
+++ b/Editor/tests/dom/tracking-removeNodeButKeepChildren-expected.html
@@ -1,7 +1,8 @@
 <html>
   <head>
   </head>
-  <body>-
+  <body>
+    -
 Before: positions[0] = (BODY,0)
 Before: positions[1] = (P#p1,0)
 Before: positions[2] = "|ab"
@@ -81,5 +82,6 @@
 After: positions[36] = "\n|\n"
 After: positions[37] = "\n\n|"
 After: positions[38] = (BODY,6) - changed from (BODY,4)
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-replaceElement-expected.html b/Editor/tests/dom/tracking-replaceElement-expected.html
index a3e6149..a83cfa6 100644
--- a/Editor/tests/dom/tracking-replaceElement-expected.html
+++ b/Editor/tests/dom/tracking-replaceElement-expected.html
@@ -1,7 +1,8 @@
 <html>
   <head>
   </head>
-  <body>-
+  <body>
+    -
 Before: positions[0] = (BODY,0)
 Before: positions[1] = (P#p1,0)
 Before: positions[2] = "|ab"
@@ -81,5 +82,6 @@
 After: positions[36] = "\n|\n"
 After: positions[37] = "\n\n|"
 After: positions[38] = (BODY,4)
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-text1-expected.html b/Editor/tests/dom/tracking-text1-expected.html
index c2814ab..964c4f3 100644
--- a/Editor/tests/dom/tracking-text1-expected.html
+++ b/Editor/tests/dom/tracking-text1-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 Before text change:
 positions[0] = "|Here is some text"
 positions[1] = "H|ere is some text"
@@ -39,5 +40,6 @@
 positions[15] = "Here is te|xt"
 positions[16] = "Here is tex|t"
 positions[17] = "Here is text|"
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-text2-expected.html b/Editor/tests/dom/tracking-text2-expected.html
index f435e11..d5c122d 100644
--- a/Editor/tests/dom/tracking-text2-expected.html
+++ b/Editor/tests/dom/tracking-text2-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 Before text change:
 positions[0] = "|Here is some text"
 positions[1] = "H|ere is some text"
@@ -39,5 +40,6 @@
 positions[15] = "is some te|xt"
 positions[16] = "is some tex|t"
 positions[17] = "is some text|"
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-text3-expected.html b/Editor/tests/dom/tracking-text3-expected.html
index 57b328e..1df6e5d 100644
--- a/Editor/tests/dom/tracking-text3-expected.html
+++ b/Editor/tests/dom/tracking-text3-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 Before text change:
 positions[0] = "|Here is some text"
 positions[1] = "H|ere is some text"
@@ -39,5 +40,6 @@
 positions[15] = "Here is some|"
 positions[16] = "Here is some|"
 positions[17] = "Here is some|"
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-text4-expected.html b/Editor/tests/dom/tracking-text4-expected.html
index 1339a49..6103a83 100644
--- a/Editor/tests/dom/tracking-text4-expected.html
+++ b/Editor/tests/dom/tracking-text4-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 Before text change:
 positions[0] = "|Here is some text"
 positions[1] = "H|ere is some text"
@@ -39,5 +40,6 @@
 positions[15] = "Here is (inserted)some te|xt"
 positions[16] = "Here is (inserted)some tex|t"
 positions[17] = "Here is (inserted)some text|"
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-text5-expected.html b/Editor/tests/dom/tracking-text5-expected.html
index a60a0ea..f935774 100644
--- a/Editor/tests/dom/tracking-text5-expected.html
+++ b/Editor/tests/dom/tracking-text5-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 Before text change:
 positions[0] = "|Here is some text"
 positions[1] = "H|ere is some text"
@@ -39,5 +40,6 @@
 positions[15] = "(inserted)Here is some te|xt"
 positions[16] = "(inserted)Here is some tex|t"
 positions[17] = "(inserted)Here is some text|"
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-text6-expected.html b/Editor/tests/dom/tracking-text6-expected.html
index 81f5d4f..0f5ab29 100644
--- a/Editor/tests/dom/tracking-text6-expected.html
+++ b/Editor/tests/dom/tracking-text6-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 Before text change:
 positions[0] = "|Here is some text"
 positions[1] = "H|ere is some text"
@@ -39,5 +40,6 @@
 positions[15] = "Here is some te|xt(inserted)"
 positions[16] = "Here is some tex|t(inserted)"
 positions[17] = "Here is some text|(inserted)"
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-text7-expected.html b/Editor/tests/dom/tracking-text7-expected.html
index 5b65f1b..6e62c11 100644
--- a/Editor/tests/dom/tracking-text7-expected.html
+++ b/Editor/tests/dom/tracking-text7-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 Before text change:
 positions[0] = "|Here is some text"
 positions[1] = "H|ere is some text"
@@ -39,5 +40,6 @@
 positions[15] = "Here is (inserted)te|xt"
 positions[16] = "Here is (inserted)tex|t"
 positions[17] = "Here is (inserted)text|"
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-text8-expected.html b/Editor/tests/dom/tracking-text8-expected.html
index 5e9ba61..7fff8bb 100644
--- a/Editor/tests/dom/tracking-text8-expected.html
+++ b/Editor/tests/dom/tracking-text8-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 Before text change:
 positions[0] = "|Here is some text"
 positions[1] = "H|ere is some text"
@@ -39,5 +40,6 @@
 positions[15] = "(inserted) is some te|xt"
 positions[16] = "(inserted) is some tex|t"
 positions[17] = "(inserted) is some text|"
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-text9-expected.html b/Editor/tests/dom/tracking-text9-expected.html
index a6a11f4..369dd26 100644
--- a/Editor/tests/dom/tracking-text9-expected.html
+++ b/Editor/tests/dom/tracking-text9-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 Before text change:
 positions[0] = "|Here is some text"
 positions[1] = "H|ere is some text"
@@ -39,5 +40,6 @@
 positions[15] = "te|xt(inserted)"
 positions[16] = "tex|t(inserted)"
 positions[17] = "text|(inserted)"
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking-wrapNode-expected.html b/Editor/tests/dom/tracking-wrapNode-expected.html
index 0e52b3f..7012054 100644
--- a/Editor/tests/dom/tracking-wrapNode-expected.html
+++ b/Editor/tests/dom/tracking-wrapNode-expected.html
@@ -1,7 +1,8 @@
 <html>
   <head>
   </head>
-  <body>-
+  <body>
+    -
 Before: positions[0] = (BODY,0)
 Before: positions[1] = (P#p1,0)
 Before: positions[2] = "|ab"
@@ -61,5 +62,6 @@
 After: positions[26] = "\n|\n"
 After: positions[27] = "\n\n|"
 After: positions[28] = (BODY,4)
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking1-expected.html b/Editor/tests/dom/tracking1-expected.html
index e058641..a4bd0ab 100644
--- a/Editor/tests/dom/tracking1-expected.html
+++ b/Editor/tests/dom/tracking1-expected.html
@@ -1,6 +1,7 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 posOffset 0, nodeOffset 0: (BODY,0) (BODY,0) (BODY,0)
 posOffset 0, nodeOffset 1: (BODY,0) (BODY,0) (BODY,0)
 posOffset 0, nodeOffset 2: (BODY,0) (BODY,0) (BODY,0)
@@ -26,5 +27,6 @@
 posOffset 4, nodeOffset 2: (BODY,4) (BODY,5) (BODY,4)
 posOffset 4, nodeOffset 3: (BODY,4) (BODY,5) (BODY,4)
 posOffset 4, nodeOffset 4: (BODY,4) (BODY,4) (BODY,4)
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/dom/tracking2-expected.html b/Editor/tests/dom/tracking2-expected.html
index 33a85ba..bfde537 100644
--- a/Editor/tests/dom/tracking2-expected.html
+++ b/Editor/tests/dom/tracking2-expected.html
@@ -1,9 +1,11 @@
 <html>
   <head></head>
-  <body>-
+  <body>
+    -
 Before insertion: position = (BODY,4)
 After insertion: position = (BODY,4)
 Before removal: position = (BODY,4)
 After removal: position = (BODY,4)
--</body>
+-
+  </body>
 </html>
diff --git a/Editor/tests/figures/FiguresTest.js b/Editor/tests/figures/FiguresTest.js
index bae29c1..385017a 100644
--- a/Editor/tests/figures/FiguresTest.js
+++ b/Editor/tests/figures/FiguresTest.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function figurePropertiesString(index)
 {
diff --git a/Editor/tests/figures/insertFigure-hierarchy01-expected.html b/Editor/tests/figures/insertFigure-hierarchy01-expected.html
index 264929e..e2892dc 100644
--- a/Editor/tests/figures/insertFigure-hierarchy01-expected.html
+++ b/Editor/tests/figures/insertFigure-hierarchy01-expected.html
@@ -7,6 +7,8 @@
       <img src="nothing.png"/>
       <figcaption>First figure</figcaption>
     </figure>
-    <figure id="item2"><img src="nothing.png"/></figure>
+    <figure id="item2">
+      <img src="nothing.png"/>
+    </figure>
   </body>
 </html>
diff --git a/Editor/tests/figures/insertFigure01-expected.html b/Editor/tests/figures/insertFigure01-expected.html
index b4683f9..637519d 100644
--- a/Editor/tests/figures/insertFigure01-expected.html
+++ b/Editor/tests/figures/insertFigure01-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><figure id="item1"><img src="nothing.png"/></figure></body>
+  <body>
+    <figure id="item1">
+      <img src="nothing.png"/>
+    </figure>
+  </body>
 </html>
diff --git a/Editor/tests/figures/insertFigure02-expected.html b/Editor/tests/figures/insertFigure02-expected.html
index ea52654..a26e458 100644
--- a/Editor/tests/figures/insertFigure02-expected.html
+++ b/Editor/tests/figures/insertFigure02-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><figure id="item1"><img src="nothing.png" style="width: 60%"/></figure></body>
+  <body>
+    <figure id="item1">
+      <img src="nothing.png" style="width: 60%"/>
+    </figure>
+  </body>
 </html>
diff --git a/Editor/tests/figures/setProperties01-expected.html b/Editor/tests/figures/setProperties01-expected.html
index 2517473..846b467 100644
--- a/Editor/tests/figures/setProperties01-expected.html
+++ b/Editor/tests/figures/setProperties01-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><figure id="item1"><img src="nothing.png" style="width: 50%"/></figure></body>
+  <body>
+    <figure id="item1">
+      <img src="nothing.png" style="width: 50%"/>
+    </figure>
+  </body>
 </html>
diff --git a/Editor/tests/figures/setProperties02-expected.html b/Editor/tests/figures/setProperties02-expected.html
index b4683f9..637519d 100644
--- a/Editor/tests/figures/setProperties02-expected.html
+++ b/Editor/tests/figures/setProperties02-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><figure id="item1"><img src="nothing.png"/></figure></body>
+  <body>
+    <figure id="item1">
+      <img src="nothing.png"/>
+    </figure>
+  </body>
 </html>
diff --git a/Editor/tests/figures/setProperties03-expected.html b/Editor/tests/figures/setProperties03-expected.html
index 6b066f9..b781301 100644
--- a/Editor/tests/figures/setProperties03-expected.html
+++ b/Editor/tests/figures/setProperties03-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><figure id="item1"><img src="other.png" style="width: 20%"/></figure></body>
+  <body>
+    <figure id="item1">
+      <img src="other.png" style="width: 20%"/>
+    </figure>
+  </body>
 </html>
diff --git a/Editor/tests/figures/setProperties04-expected.html b/Editor/tests/figures/setProperties04-expected.html
index 27a2b34..1ce2a75 100644
--- a/Editor/tests/figures/setProperties04-expected.html
+++ b/Editor/tests/figures/setProperties04-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><figure id="item1"><img style="width: 20%"/></figure></body>
+  <body>
+    <figure id="item1">
+      <img style="width: 20%"/>
+    </figure>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/classNames01-expected.html b/Editor/tests/formatting/classNames01-expected.html
index 209197d..a988afe 100644
--- a/Editor/tests/formatting/classNames01-expected.html
+++ b/Editor/tests/formatting/classNames01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p class="test">Sample text</p></body>
+  <body>
+    <p class="test">Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/classNames02-expected.html b/Editor/tests/formatting/classNames02-expected.html
index 935458b..a34d57e 100644
--- a/Editor/tests/formatting/classNames02-expected.html
+++ b/Editor/tests/formatting/classNames02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Sample text</h1></body>
+  <body>
+    <h1>Sample text</h1>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/classNames03-expected.html b/Editor/tests/formatting/classNames03-expected.html
index 935458b..a34d57e 100644
--- a/Editor/tests/formatting/classNames03-expected.html
+++ b/Editor/tests/formatting/classNames03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Sample text</h1></body>
+  <body>
+    <h1>Sample text</h1>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/classNames04-expected.html b/Editor/tests/formatting/classNames04-expected.html
index 209197d..a988afe 100644
--- a/Editor/tests/formatting/classNames04-expected.html
+++ b/Editor/tests/formatting/classNames04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p class="test">Sample text</p></body>
+  <body>
+    <p class="test">Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/classNames05-expected.html b/Editor/tests/formatting/classNames05-expected.html
index 2d1beeb..756d54b 100644
--- a/Editor/tests/formatting/classNames05-expected.html
+++ b/Editor/tests/formatting/classNames05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h2 class="test">Sample text</h2></body>
+  <body>
+    <h2 class="test">Sample text</h2>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/classNames06-expected.html b/Editor/tests/formatting/classNames06-expected.html
index b691bda..966e4ad 100644
--- a/Editor/tests/formatting/classNames06-expected.html
+++ b/Editor/tests/formatting/classNames06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample text</p></body>
+  <body>
+    <p>Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/classNames07-expected.html b/Editor/tests/formatting/classNames07-expected.html
index 935458b..a34d57e 100644
--- a/Editor/tests/formatting/classNames07-expected.html
+++ b/Editor/tests/formatting/classNames07-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Sample text</h1></body>
+  <body>
+    <h1>Sample text</h1>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/classNames08-expected.html b/Editor/tests/formatting/classNames08-expected.html
index 935458b..a34d57e 100644
--- a/Editor/tests/formatting/classNames08-expected.html
+++ b/Editor/tests/formatting/classNames08-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>Sample text</h1></body>
+  <body>
+    <h1>Sample text</h1>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/empty05-expected.html b/Editor/tests/formatting/empty05-expected.html
index 74641c9..ee0a065 100644
--- a/Editor/tests/formatting/empty05-expected.html
+++ b/Editor/tests/formatting/empty05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>a[]</b></p></body>
+  <body>
+    <p><b>a[]</b></p>
+  </body>
 </html>
\ No newline at end of file
diff --git a/Editor/tests/formatting/empty06-expected.html b/Editor/tests/formatting/empty06-expected.html
index d784c8f..e673975 100644
--- a/Editor/tests/formatting/empty06-expected.html
+++ b/Editor/tests/formatting/empty06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>a[]</b></p></body>
+  <body>
+    <p><b>a[]</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/empty07-expected.html b/Editor/tests/formatting/empty07-expected.html
index cb6a59d..259fd6e 100644
--- a/Editor/tests/formatting/empty07-expected.html
+++ b/Editor/tests/formatting/empty07-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li><p><b>a[]</b></p></li></ul></body>
+  <body>
+    <ul>
+      <li><p><b>a[]</b></p></li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/getFormatting02-expected.html b/Editor/tests/formatting/getFormatting02-expected.html
index 9d2737d..f2ad17d 100644
--- a/Editor/tests/formatting/getFormatting02-expected.html
+++ b/Editor/tests/formatting/getFormatting02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>-uxwrite-paragraph-style = p</p></body>
+  <body>
+    <p>-uxwrite-paragraph-style = p</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/getFormatting03-expected.html b/Editor/tests/formatting/getFormatting03-expected.html
index 9d2737d..f2ad17d 100644
--- a/Editor/tests/formatting/getFormatting03-expected.html
+++ b/Editor/tests/formatting/getFormatting03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>-uxwrite-paragraph-style = p</p></body>
+  <body>
+    <p>-uxwrite-paragraph-style = p</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/getFormatting10-expected.html b/Editor/tests/formatting/getFormatting10-expected.html
index e125e49..21a0838 100644
--- a/Editor/tests/formatting/getFormatting10-expected.html
+++ b/Editor/tests/formatting/getFormatting10-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>-uxwrite-paragraph-style = p.test</p></body>
+  <body>
+    <p>-uxwrite-paragraph-style = p.test</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/getFormatting11-expected.html b/Editor/tests/formatting/getFormatting11-expected.html
index e4009fd..2e704f5 100644
--- a/Editor/tests/formatting/getFormatting11-expected.html
+++ b/Editor/tests/formatting/getFormatting11-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>-uxwrite-paragraph-style = h1</p></body>
+  <body>
+    <p>-uxwrite-paragraph-style = h1</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-change01-expected.html b/Editor/tests/formatting/inline-change01-expected.html
index 7d3d2ac..481c064 100644
--- a/Editor/tests/formatting/inline-change01-expected.html
+++ b/Editor/tests/formatting/inline-change01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><s style="color: red">Text</s></p></body>
+  <body>
+    <p><s style="color: red">Text</s></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-change02-expected.html b/Editor/tests/formatting/inline-change02-expected.html
index 7d3d2ac..481c064 100644
--- a/Editor/tests/formatting/inline-change02-expected.html
+++ b/Editor/tests/formatting/inline-change02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><s style="color: red">Text</s></p></body>
+  <body>
+    <p><s style="color: red">Text</s></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-change03-expected.html b/Editor/tests/formatting/inline-change03-expected.html
index 7eab119..e747faf 100644
--- a/Editor/tests/formatting/inline-change03-expected.html
+++ b/Editor/tests/formatting/inline-change03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="color: red"><s>Text</s></p></body>
+  <body>
+    <p style="color: red"><s>Text</s></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-change04-expected.html b/Editor/tests/formatting/inline-change04-expected.html
index 7d3d2ac..481c064 100644
--- a/Editor/tests/formatting/inline-change04-expected.html
+++ b/Editor/tests/formatting/inline-change04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><s style="color: red">Text</s></p></body>
+  <body>
+    <p><s style="color: red">Text</s></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-change05-expected.html b/Editor/tests/formatting/inline-change05-expected.html
index 7d3d2ac..481c064 100644
--- a/Editor/tests/formatting/inline-change05-expected.html
+++ b/Editor/tests/formatting/inline-change05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><s style="color: red">Text</s></p></body>
+  <body>
+    <p><s style="color: red">Text</s></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-change06-expected.html b/Editor/tests/formatting/inline-change06-expected.html
index 7eab119..e747faf 100644
--- a/Editor/tests/formatting/inline-change06-expected.html
+++ b/Editor/tests/formatting/inline-change06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="color: red"><s>Text</s></p></body>
+  <body>
+    <p style="color: red"><s>Text</s></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-endnote01-expected.html b/Editor/tests/formatting/inline-endnote01-expected.html
new file mode 100644
index 0000000..984c59c
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote01-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <b>[two]</b>
+      three
+      <span class="endnote">four</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote01-input.html b/Editor/tests/formatting/inline-endnote01-input.html
new file mode 100644
index 0000000..e21130b
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote01-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"font-weight": "bold"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one [two] three <span class="endnote">four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote02-expected.html b/Editor/tests/formatting/inline-endnote02-expected.html
new file mode 100644
index 0000000..2d0bd0c
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote02-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span style="color: red">[two]</span>
+      three
+      <span class="endnote">four</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote02-input.html b/Editor/tests/formatting/inline-endnote02-input.html
new file mode 100644
index 0000000..165b67d
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote02-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"color": "red"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one [two] three <span class="endnote">four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote03-expected.html b/Editor/tests/formatting/inline-endnote03-expected.html
new file mode 100644
index 0000000..4c9d6c4
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote03-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="endnote">two</span>
+      three
+      <b>[four]</b>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote03-input.html b/Editor/tests/formatting/inline-endnote03-input.html
new file mode 100644
index 0000000..33244d5
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote03-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"font-weight": "bold"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one <span class="endnote">two</span> three [four] five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote04-expected.html b/Editor/tests/formatting/inline-endnote04-expected.html
new file mode 100644
index 0000000..7e25e59
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote04-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="endnote">two</span>
+      three
+      <span style="color: red">[four]</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote04-input.html b/Editor/tests/formatting/inline-endnote04-input.html
new file mode 100644
index 0000000..3e965f5
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote04-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"color": "red"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one <span class="endnote">two</span> three [four] five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote05-expected.html b/Editor/tests/formatting/inline-endnote05-expected.html
new file mode 100644
index 0000000..e8e64ae
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote05-expected.html
@@ -0,0 +1,14 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="endnote">
+        two
+        <b>[three]</b>
+        four
+      </span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote05-input.html b/Editor/tests/formatting/inline-endnote05-input.html
new file mode 100644
index 0000000..672d698
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote05-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"font-weight": "bold"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one <span class="endnote">two [three] four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote06-expected.html b/Editor/tests/formatting/inline-endnote06-expected.html
new file mode 100644
index 0000000..7b676ac
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote06-expected.html
@@ -0,0 +1,14 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="endnote">
+        two
+        <span style="color: red">[three]</span>
+        four
+      </span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-endnote06-input.html b/Editor/tests/formatting/inline-endnote06-input.html
new file mode 100644
index 0000000..daf5a7d
--- /dev/null
+++ b/Editor/tests/formatting/inline-endnote06-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"color": "red"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one <span class="endnote">two [three] four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote01-expected.html b/Editor/tests/formatting/inline-footnote01-expected.html
new file mode 100644
index 0000000..407cc39
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote01-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <b>[two]</b>
+      three
+      <span class="footnote">four</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote01-input.html b/Editor/tests/formatting/inline-footnote01-input.html
new file mode 100644
index 0000000..50f66fe
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote01-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"font-weight": "bold"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one [two] three <span class="footnote">four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote02-expected.html b/Editor/tests/formatting/inline-footnote02-expected.html
new file mode 100644
index 0000000..c679c9a
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote02-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span style="color: red">[two]</span>
+      three
+      <span class="footnote">four</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote02-input.html b/Editor/tests/formatting/inline-footnote02-input.html
new file mode 100644
index 0000000..7bf7ee4
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote02-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"color": "red"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one [two] three <span class="footnote">four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote03-expected.html b/Editor/tests/formatting/inline-footnote03-expected.html
new file mode 100644
index 0000000..2aa73ad
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote03-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="footnote">two</span>
+      three
+      <b>[four]</b>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote03-input.html b/Editor/tests/formatting/inline-footnote03-input.html
new file mode 100644
index 0000000..6fe6601
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote03-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"font-weight": "bold"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one <span class="footnote">two</span> three [four] five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote04-expected.html b/Editor/tests/formatting/inline-footnote04-expected.html
new file mode 100644
index 0000000..b1ef955
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote04-expected.html
@@ -0,0 +1,12 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="footnote">two</span>
+      three
+      <span style="color: red">[four]</span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote04-input.html b/Editor/tests/formatting/inline-footnote04-input.html
new file mode 100644
index 0000000..23f07d4
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote04-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"color": "red"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one <span class="footnote">two</span> three [four] five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote05-expected.html b/Editor/tests/formatting/inline-footnote05-expected.html
new file mode 100644
index 0000000..91a8092
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote05-expected.html
@@ -0,0 +1,14 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="footnote">
+        two
+        <b>[three]</b>
+        four
+      </span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote05-input.html b/Editor/tests/formatting/inline-footnote05-input.html
new file mode 100644
index 0000000..2b45eac
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote05-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"font-weight": "bold"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one <span class="footnote">two [three] four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote06-expected.html b/Editor/tests/formatting/inline-footnote06-expected.html
new file mode 100644
index 0000000..9ecb197
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote06-expected.html
@@ -0,0 +1,14 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      one
+      <span class="footnote">
+        two
+        <span style="color: red">[three]</span>
+        four
+      </span>
+      five
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/formatting/inline-footnote06-input.html b/Editor/tests/formatting/inline-footnote06-input.html
new file mode 100644
index 0000000..b19e110
--- /dev/null
+++ b/Editor/tests/formatting/inline-footnote06-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function performTest()
+{
+    Formatting_applyFormattingChanges(null,{"color": "red"});
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <p>one <span class="footnote">two [three] four</span> five</p>
+</body>
+</html>
diff --git a/Editor/tests/formatting/inline-remove01-expected.html b/Editor/tests/formatting/inline-remove01-expected.html
index 02e36f9..b51a95a 100644
--- a/Editor/tests/formatting/inline-remove01-expected.html
+++ b/Editor/tests/formatting/inline-remove01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><s>Text</s></p></body>
+  <body>
+    <p><s>Text</s></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-remove02-expected.html b/Editor/tests/formatting/inline-remove02-expected.html
index 1b144a1..2c9f2b7 100644
--- a/Editor/tests/formatting/inline-remove02-expected.html
+++ b/Editor/tests/formatting/inline-remove02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><s style="font-size: 18pt">Text</s></p></body>
+  <body>
+    <p><s style="font-size: 18pt">Text</s></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-remove05-expected.html b/Editor/tests/formatting/inline-remove05-expected.html
index 6d09348..fd43031 100644
--- a/Editor/tests/formatting/inline-remove05-expected.html
+++ b/Editor/tests/formatting/inline-remove05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><s style="color: blue">Text</s></p></body>
+  <body>
+    <p><s style="color: blue">Text</s></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-remove06-expected.html b/Editor/tests/formatting/inline-remove06-expected.html
index 04b6311..39d4589 100644
--- a/Editor/tests/formatting/inline-remove06-expected.html
+++ b/Editor/tests/formatting/inline-remove06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b><s>Text</s></b></p></body>
+  <body>
+    <p><b><s>Text</s></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-remove07-expected.html b/Editor/tests/formatting/inline-remove07-expected.html
index 16a7ff2..b6836e0 100644
--- a/Editor/tests/formatting/inline-remove07-expected.html
+++ b/Editor/tests/formatting/inline-remove07-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><i><s>Text</s></i></p></body>
+  <body>
+    <p><i><s>Text</s></i></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-remove08-expected.html b/Editor/tests/formatting/inline-remove08-expected.html
index 0c70e5c..5e43b82 100644
--- a/Editor/tests/formatting/inline-remove08-expected.html
+++ b/Editor/tests/formatting/inline-remove08-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><u><s>Text</s></u></p></body>
+  <body>
+    <p><u><s>Text</s></u></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-remove09-expected.html b/Editor/tests/formatting/inline-remove09-expected.html
index d2fb84b..06d2712 100644
--- a/Editor/tests/formatting/inline-remove09-expected.html
+++ b/Editor/tests/formatting/inline-remove09-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><s><s>Text</s></s></p></body>
+  <body>
+    <p><s><s>Text</s></s></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-remove10-expected.html b/Editor/tests/formatting/inline-remove10-expected.html
index 6d82c78..26b646b 100644
--- a/Editor/tests/formatting/inline-remove10-expected.html
+++ b/Editor/tests/formatting/inline-remove10-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><span style="font-size: 18pt">Text</span></p></body>
+  <body>
+    <p><span style="font-size: 18pt">Text</span></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-remove11-expected.html b/Editor/tests/formatting/inline-remove11-expected.html
index e3d1cf1..77761d1 100644
--- a/Editor/tests/formatting/inline-remove11-expected.html
+++ b/Editor/tests/formatting/inline-remove11-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Text</p></body>
+  <body>
+    <p>Text</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-remove12-expected.html b/Editor/tests/formatting/inline-remove12-expected.html
index e3d1cf1..77761d1 100644
--- a/Editor/tests/formatting/inline-remove12-expected.html
+++ b/Editor/tests/formatting/inline-remove12-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Text</p></body>
+  <body>
+    <p>Text</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-set01-nop-expected.html b/Editor/tests/formatting/inline-set01-nop-expected.html
index a2376d2..e09a322 100644
--- a/Editor/tests/formatting/inline-set01-nop-expected.html
+++ b/Editor/tests/formatting/inline-set01-nop-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><span style="color: blue; font-size: 12pt">Sample text</span></body>
+  <body>
+    <span style="color: blue; font-size: 12pt">Sample text</span>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-set01-outer-expected.html b/Editor/tests/formatting/inline-set01-outer-expected.html
index 4cd2eae..e0e0797 100644
--- a/Editor/tests/formatting/inline-set01-outer-expected.html
+++ b/Editor/tests/formatting/inline-set01-outer-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="color: blue; font-size: 12pt">Sample text</p></body>
+  <body>
+    <p style="color: blue; font-size: 12pt">Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-set01-p-expected.html b/Editor/tests/formatting/inline-set01-p-expected.html
index 4cd2eae..e0e0797 100644
--- a/Editor/tests/formatting/inline-set01-p-expected.html
+++ b/Editor/tests/formatting/inline-set01-p-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="color: blue; font-size: 12pt">Sample text</p></body>
+  <body>
+    <p style="color: blue; font-size: 12pt">Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-set03-nop-expected.html b/Editor/tests/formatting/inline-set03-nop-expected.html
index aca72bf..48755bd 100644
--- a/Editor/tests/formatting/inline-set03-nop-expected.html
+++ b/Editor/tests/formatting/inline-set03-nop-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><b>Sample text</b></body>
+  <body>
+    <b>Sample text</b>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-set03-outer-expected.html b/Editor/tests/formatting/inline-set03-outer-expected.html
index 9a38b37..d79a0f8 100644
--- a/Editor/tests/formatting/inline-set03-outer-expected.html
+++ b/Editor/tests/formatting/inline-set03-outer-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>Sample text</b></p></body>
+  <body>
+    <p><b>Sample text</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-set03-p-expected.html b/Editor/tests/formatting/inline-set03-p-expected.html
index 9a38b37..d79a0f8 100644
--- a/Editor/tests/formatting/inline-set03-p-expected.html
+++ b/Editor/tests/formatting/inline-set03-p-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>Sample text</b></p></body>
+  <body>
+    <p><b>Sample text</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/inline-set04-expected.html b/Editor/tests/formatting/inline-set04-expected.html
index d26dd5b..300d365 100644
--- a/Editor/tests/formatting/inline-set04-expected.html
+++ b/Editor/tests/formatting/inline-set04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b><i><u>Sample text</u></i></b></p></body>
+  <body>
+    <p><b><i><u>Sample text</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/justCursor03-expected.html b/Editor/tests/formatting/justCursor03-expected.html
index a6c01c0..b0014b5 100644
--- a/Editor/tests/formatting/justCursor03-expected.html
+++ b/Editor/tests/formatting/justCursor03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="text-align: center">Here is sXome text</p></body>
+  <body>
+    <p style="text-align: center">Here is sXome text</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/mergeUpwards01-expected.html b/Editor/tests/formatting/mergeUpwards01-expected.html
index 7d3258f..a1738e6 100644
--- a/Editor/tests/formatting/mergeUpwards01-expected.html
+++ b/Editor/tests/formatting/mergeUpwards01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>One two []three</b></p></body>
+  <body>
+    <p><b>One two []three</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/mergeUpwards02-expected.html b/Editor/tests/formatting/mergeUpwards02-expected.html
index 38e2cb0..372f917 100644
--- a/Editor/tests/formatting/mergeUpwards02-expected.html
+++ b/Editor/tests/formatting/mergeUpwards02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b><i><u>One two []three</u></i></b></p></body>
+  <body>
+    <p><b><i><u>One two []three</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/mergeUpwards05-expected.html b/Editor/tests/formatting/mergeUpwards05-expected.html
index 652300e..6be8697 100644
--- a/Editor/tests/formatting/mergeUpwards05-expected.html
+++ b/Editor/tests/formatting/mergeUpwards05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>[]One two three</p></body>
+  <body>
+    <p>[]One two three</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/mergeUpwards06-expected.html b/Editor/tests/formatting/mergeUpwards06-expected.html
index 652300e..6be8697 100644
--- a/Editor/tests/formatting/mergeUpwards06-expected.html
+++ b/Editor/tests/formatting/mergeUpwards06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>[]One two three</p></body>
+  <body>
+    <p>[]One two three</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/mergeUpwards07-expected.html b/Editor/tests/formatting/mergeUpwards07-expected.html
index 652300e..6be8697 100644
--- a/Editor/tests/formatting/mergeUpwards07-expected.html
+++ b/Editor/tests/formatting/mergeUpwards07-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>[]One two three</p></body>
+  <body>
+    <p>[]One two three</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/mergeUpwards08-expected.html b/Editor/tests/formatting/mergeUpwards08-expected.html
index 652300e..6be8697 100644
--- a/Editor/tests/formatting/mergeUpwards08-expected.html
+++ b/Editor/tests/formatting/mergeUpwards08-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>[]One two three</p></body>
+  <body>
+    <p>[]One two three</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-change01-expected.html b/Editor/tests/formatting/paragraph-change01-expected.html
index 75764a2..4441b53 100644
--- a/Editor/tests/formatting/paragraph-change01-expected.html
+++ b/Editor/tests/formatting/paragraph-change01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="margin-left: 20%"></p></body>
+  <body>
+    <p style="margin-left: 20%"></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-change02-expected.html b/Editor/tests/formatting/paragraph-change02-expected.html
index 2a887b0..2fcd240 100644
--- a/Editor/tests/formatting/paragraph-change02-expected.html
+++ b/Editor/tests/formatting/paragraph-change02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="margin-left: 20%"/></body>
+  <body>
+    <p style="margin-left: 20%"/>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-change03-expected.html b/Editor/tests/formatting/paragraph-change03-expected.html
index e34a177..86f379f 100644
--- a/Editor/tests/formatting/paragraph-change03-expected.html
+++ b/Editor/tests/formatting/paragraph-change03-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p style="margin-left: 10%">One</p>
     <h1 style="margin-left: 10%">Two</h1>
-    <div style="margin-left: 10%">Three</div>
+    <div style="margin-left: 10%">
+      Three
+    </div>
   </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-change04-expected.html b/Editor/tests/formatting/paragraph-change04-expected.html
index e34a177..86f379f 100644
--- a/Editor/tests/formatting/paragraph-change04-expected.html
+++ b/Editor/tests/formatting/paragraph-change04-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p style="margin-left: 10%">One</p>
     <h1 style="margin-left: 10%">Two</h1>
-    <div style="margin-left: 10%">Three</div>
+    <div style="margin-left: 10%">
+      Three
+    </div>
   </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-change05-expected.html b/Editor/tests/formatting/paragraph-change05-expected.html
index d1c949b..65d536e 100644
--- a/Editor/tests/formatting/paragraph-change05-expected.html
+++ b/Editor/tests/formatting/paragraph-change05-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p style="margin-left: 1%">One</p>
     <h1 style="margin-left: 10%">Two</h1>
-    <div style="margin-left: 3%">Three</div>
+    <div style="margin-left: 3%">
+      Three
+    </div>
   </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-remove01-expected.html b/Editor/tests/formatting/paragraph-remove01-expected.html
index 9b57168..4424e4d 100644
--- a/Editor/tests/formatting/paragraph-remove01-expected.html
+++ b/Editor/tests/formatting/paragraph-remove01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p></p></body>
+  <body>
+    <p></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-remove02-expected.html b/Editor/tests/formatting/paragraph-remove02-expected.html
index a1ea0ac..572de6d 100644
--- a/Editor/tests/formatting/paragraph-remove02-expected.html
+++ b/Editor/tests/formatting/paragraph-remove02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="margin-right: 20%"></p></body>
+  <body>
+    <p style="margin-right: 20%"></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-remove03-expected.html b/Editor/tests/formatting/paragraph-remove03-expected.html
index d45c18b..aec2fa1 100644
--- a/Editor/tests/formatting/paragraph-remove03-expected.html
+++ b/Editor/tests/formatting/paragraph-remove03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="margin-right: 20%"/></body>
+  <body>
+    <p style="margin-right: 20%"/>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-remove04-expected.html b/Editor/tests/formatting/paragraph-remove04-expected.html
index c0ed067..22f5569 100644
--- a/Editor/tests/formatting/paragraph-remove04-expected.html
+++ b/Editor/tests/formatting/paragraph-remove04-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p>One</p>
     <h1>Two</h1>
-    <div>Three</div>
+    <div>
+      Three
+    </div>
   </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-remove05-expected.html b/Editor/tests/formatting/paragraph-remove05-expected.html
index c2b1587..6381bf2 100644
--- a/Editor/tests/formatting/paragraph-remove05-expected.html
+++ b/Editor/tests/formatting/paragraph-remove05-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p style="margin-left: 1%">One</p>
     <h1>Two</h1>
-    <div style="margin-left: 3%">Three</div>
+    <div style="margin-left: 3%">
+      Three
+    </div>
   </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-remove06-expected.html b/Editor/tests/formatting/paragraph-remove06-expected.html
index fd31291..dd1cec2 100644
--- a/Editor/tests/formatting/paragraph-remove06-expected.html
+++ b/Editor/tests/formatting/paragraph-remove06-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p style="margin-left: 1%; margin-right: 11%">One</p>
     <h1 style="margin-right: 22%">Two</h1>
-    <div style="margin-left: 3%; margin-right: 33%">Three</div>
+    <div style="margin-left: 3%; margin-right: 33%">
+      Three
+    </div>
   </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-set01-expected.html b/Editor/tests/formatting/paragraph-set01-expected.html
index c8f7f18..7c2d2d8 100644
--- a/Editor/tests/formatting/paragraph-set01-expected.html
+++ b/Editor/tests/formatting/paragraph-set01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="margin-left: 10%"></p></body>
+  <body>
+    <p style="margin-left: 10%"></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-set02-expected.html b/Editor/tests/formatting/paragraph-set02-expected.html
index 9cb08ff..63b2469 100644
--- a/Editor/tests/formatting/paragraph-set02-expected.html
+++ b/Editor/tests/formatting/paragraph-set02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="margin-left: 10%"/></body>
+  <body>
+    <p style="margin-left: 10%"/>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-set03-expected.html b/Editor/tests/formatting/paragraph-set03-expected.html
index e34a177..86f379f 100644
--- a/Editor/tests/formatting/paragraph-set03-expected.html
+++ b/Editor/tests/formatting/paragraph-set03-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p style="margin-left: 10%">One</p>
     <h1 style="margin-left: 10%">Two</h1>
-    <div style="margin-left: 10%">Three</div>
+    <div style="margin-left: 10%">
+      Three
+    </div>
   </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-set04-expected.html b/Editor/tests/formatting/paragraph-set04-expected.html
index e34a177..86f379f 100644
--- a/Editor/tests/formatting/paragraph-set04-expected.html
+++ b/Editor/tests/formatting/paragraph-set04-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p style="margin-left: 10%">One</p>
     <h1 style="margin-left: 10%">Two</h1>
-    <div style="margin-left: 10%">Three</div>
+    <div style="margin-left: 10%">
+      Three
+    </div>
   </body>
 </html>
diff --git a/Editor/tests/formatting/paragraph-set05-expected.html b/Editor/tests/formatting/paragraph-set05-expected.html
index f774ad7..7ce9c3e 100644
--- a/Editor/tests/formatting/paragraph-set05-expected.html
+++ b/Editor/tests/formatting/paragraph-set05-expected.html
@@ -3,6 +3,8 @@
   <body>
     <p>One</p>
     <h1 style="margin-left: 10%">Two</h1>
-    <div>Three</div>
+    <div>
+      Three
+    </div>
   </body>
 </html>
diff --git a/Editor/tests/formatting/style-nop01-expected.html b/Editor/tests/formatting/style-nop01-expected.html
index 043cc20..f2a7521 100644
--- a/Editor/tests/formatting/style-nop01-expected.html
+++ b/Editor/tests/formatting/style-nop01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><br/></p></body>
+  <body>
+    <p><br/></p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/style-nop01a-expected.html b/Editor/tests/formatting/style-nop01a-expected.html
index c0aab59..a341e6e 100644
--- a/Editor/tests/formatting/style-nop01a-expected.html
+++ b/Editor/tests/formatting/style-nop01a-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1><br/></h1></body>
+  <body>
+    <h1><br/></h1>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/style-nop02-expected.html b/Editor/tests/formatting/style-nop02-expected.html
index b4dfc65..9ef2a3e 100644
--- a/Editor/tests/formatting/style-nop02-expected.html
+++ b/Editor/tests/formatting/style-nop02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>a</p></body>
+  <body>
+    <p>a</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/style-nop03-expected.html b/Editor/tests/formatting/style-nop03-expected.html
index b4dfc65..9ef2a3e 100644
--- a/Editor/tests/formatting/style-nop03-expected.html
+++ b/Editor/tests/formatting/style-nop03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>a</p></body>
+  <body>
+    <p>a</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/style-nop04-expected.html b/Editor/tests/formatting/style-nop04-expected.html
index a243c42..68f377c 100644
--- a/Editor/tests/formatting/style-nop04-expected.html
+++ b/Editor/tests/formatting/style-nop04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>ab</p></body>
+  <body>
+    <p>ab</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/style-nop05-expected.html b/Editor/tests/formatting/style-nop05-expected.html
index b4dfc65..9ef2a3e 100644
--- a/Editor/tests/formatting/style-nop05-expected.html
+++ b/Editor/tests/formatting/style-nop05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>a</p></body>
+  <body>
+    <p>a</p>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/style-nop06-expected.html b/Editor/tests/formatting/style-nop06-expected.html
index 7e3d0f3..53e060d 100644
--- a/Editor/tests/formatting/style-nop06-expected.html
+++ b/Editor/tests/formatting/style-nop06-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><figure><p><br/></p></figure></body>
+  <body>
+    <figure>
+      <p><br/></p>
+    </figure>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/style-nop07-expected.html b/Editor/tests/formatting/style-nop07-expected.html
index 49fe284..79c288f 100644
--- a/Editor/tests/formatting/style-nop07-expected.html
+++ b/Editor/tests/formatting/style-nop07-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><figure><figcaption><p><br/></p></figcaption></figure></body>
+  <body>
+    <figure>
+      <figcaption><p><br/></p></figcaption>
+    </figure>
+  </body>
 </html>
diff --git a/Editor/tests/formatting/style-nop08-expected.html b/Editor/tests/formatting/style-nop08-expected.html
index dfc5ed4..d242935 100644
--- a/Editor/tests/formatting/style-nop08-expected.html
+++ b/Editor/tests/formatting/style-nop08-expected.html
@@ -3,7 +3,11 @@
   <body>
     <table>
       <caption><p><br/></p></caption>
-      <tbody><tr><td>Cell</td></tr></tbody>
+      <tbody>
+        <tr>
+          <td>Cell</td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/formatting/style-nop09-expected.html b/Editor/tests/formatting/style-nop09-expected.html
index 6371754..4829db4 100644
--- a/Editor/tests/formatting/style-nop09-expected.html
+++ b/Editor/tests/formatting/style-nop09-expected.html
@@ -1,4 +1,12 @@
 <html>
   <head></head>
-  <body><table><tbody><tr><td><p><br/></p></td></tr></tbody></table></body>
+  <body>
+    <table>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
+    </table>
+  </body>
 </html>
diff --git a/Editor/tests/genindex.sh b/Editor/tests/genindex.sh
index eece866..3c99da3 100755
--- a/Editor/tests/genindex.sh
+++ b/Editor/tests/genindex.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 (
 prevdir=""
-echo "// This file was generated by genindex.sh on `date`"
+echo "// This file was generated by genindex.sh"
 echo "var tests = [";
 for dir in *; do
     if [ -d $dir ]; then
diff --git a/Editor/tests/index.js b/Editor/tests/index.js
index c26d2d1..485397b 100644
--- a/Editor/tests/index.js
+++ b/Editor/tests/index.js
@@ -1,4 +1,4 @@
-// This file was generated by genindex.sh on Thu 27 Nov 2014 10:34:42 ICT
+// This file was generated by genindex.sh
 var tests = [
   { dir: "autocorrect",
     files: ["acceptCorrection-undo",
@@ -257,12 +257,34 @@
             "deleteCharacter-emoji06",
             "deleteCharacter-emoji07",
             "deleteCharacter-emoji08",
+            "deleteCharacter-endnote01",
+            "deleteCharacter-endnote02",
+            "deleteCharacter-endnote03",
+            "deleteCharacter-endnote04",
+            "deleteCharacter-endnote05",
+            "deleteCharacter-endnote06",
+            "deleteCharacter-endnote07",
+            "deleteCharacter-endnote08",
+            "deleteCharacter-endnote09",
+            "deleteCharacter-endnote10",
             "deleteCharacter-figcaption01",
             "deleteCharacter-figcaption02",
+            "deleteCharacter-figcaption03",
+            "deleteCharacter-figcaption04",
             "deleteCharacter-figure01",
             "deleteCharacter-figure02",
             "deleteCharacter-figure03",
             "deleteCharacter-figure04",
+            "deleteCharacter-footnote01",
+            "deleteCharacter-footnote02",
+            "deleteCharacter-footnote03",
+            "deleteCharacter-footnote04",
+            "deleteCharacter-footnote05",
+            "deleteCharacter-footnote06",
+            "deleteCharacter-footnote07",
+            "deleteCharacter-footnote08",
+            "deleteCharacter-footnote09",
+            "deleteCharacter-footnote10",
             "deleteCharacter-last01",
             "deleteCharacter-last02",
             "deleteCharacter-last03",
@@ -303,6 +325,8 @@
             "deleteCharacter-table02",
             "deleteCharacter-table03",
             "deleteCharacter-table04",
+            "deleteCharacter-tablecaption01",
+            "deleteCharacter-tablecaption02",
             "deleteCharacter-toc01",
             "deleteCharacter-toc02",
             "deleteCharacter-toc03",
@@ -379,8 +403,24 @@
             "enterPressed-emptyContainer07a",
             "enterPressed-emptyContainer08",
             "enterPressed-emptyContainer08a",
+            "enterPressed-endnote01",
+            "enterPressed-endnote02",
+            "enterPressed-endnote03",
+            "enterPressed-endnote04",
+            "enterPressed-endnote05",
+            "enterPressed-endnote06",
+            "enterPressed-endnote07",
+            "enterPressed-endnote08",
             "enterPressed-figcaption01",
             "enterPressed-figcaption02",
+            "enterPressed-footnote01",
+            "enterPressed-footnote02",
+            "enterPressed-footnote03",
+            "enterPressed-footnote04",
+            "enterPressed-footnote05",
+            "enterPressed-footnote06",
+            "enterPressed-footnote07",
+            "enterPressed-footnote08",
             "enterPressed-heading01",
             "enterPressed-heading02",
             "enterPressed-heading03",
@@ -580,12 +620,18 @@
             "insertEndnote04",
             "insertEndnote05",
             "insertEndnote06",
+            "insertEndnote07",
+            "insertEndnote08",
+            "insertEndnote09",
             "insertFootnote01",
             "insertFootnote02",
             "insertFootnote03",
             "insertFootnote04",
             "insertFootnote05",
             "insertFootnote06",
+            "insertFootnote07",
+            "insertFootnote08",
+            "insertFootnote09",
             "makeContainerInsertionPoint01",
             "makeContainerInsertionPoint02a",
             "makeContainerInsertionPoint02b",
@@ -721,6 +767,12 @@
             "replaceElement08",
             "replaceElement09",
             "replaceElement10",
+            "splitAroundSelection-endnote01",
+            "splitAroundSelection-endnote02",
+            "splitAroundSelection-endnote03",
+            "splitAroundSelection-footnote01",
+            "splitAroundSelection-footnote02",
+            "splitAroundSelection-footnote03",
             "splitAroundSelection-nested01",
             "splitAroundSelection-nested02",
             "splitAroundSelection-nested03",
@@ -916,6 +968,18 @@
             "inline-change20",
             "inline-change21",
             "inline-change22",
+            "inline-endnote01",
+            "inline-endnote02",
+            "inline-endnote03",
+            "inline-endnote04",
+            "inline-endnote05",
+            "inline-endnote06",
+            "inline-footnote01",
+            "inline-footnote02",
+            "inline-footnote03",
+            "inline-footnote04",
+            "inline-footnote05",
+            "inline-footnote06",
             "inline-remove01",
             "inline-remove02",
             "inline-remove03",
@@ -1571,9 +1635,33 @@
             "isValidCursorPosition-caption01a",
             "isValidCursorPosition-caption01b",
             "isValidCursorPosition-caption01c",
+            "isValidCursorPosition-endnote01",
+            "isValidCursorPosition-endnote02",
+            "isValidCursorPosition-endnote03",
+            "isValidCursorPosition-endnote04",
+            "isValidCursorPosition-endnote05",
+            "isValidCursorPosition-endnote06",
+            "isValidCursorPosition-endnote07",
+            "isValidCursorPosition-endnote08",
+            "isValidCursorPosition-endnote09",
+            "isValidCursorPosition-endnote10",
             "isValidCursorPosition-figure01a",
             "isValidCursorPosition-figure01b",
             "isValidCursorPosition-figure01c",
+            "isValidCursorPosition-footnote01",
+            "isValidCursorPosition-footnote02",
+            "isValidCursorPosition-footnote03",
+            "isValidCursorPosition-footnote04",
+            "isValidCursorPosition-footnote05",
+            "isValidCursorPosition-footnote06",
+            "isValidCursorPosition-footnote07",
+            "isValidCursorPosition-footnote08",
+            "isValidCursorPosition-footnote09",
+            "isValidCursorPosition-footnote10",
+            "isValidCursorPosition-footnote11",
+            "isValidCursorPosition-footnote12",
+            "isValidCursorPosition-footnote13",
+            "isValidCursorPosition-footnote14",
             "isValidCursorPosition-heading01a",
             "isValidCursorPosition-heading01b",
             "isValidCursorPosition-heading01c",
@@ -1963,6 +2051,8 @@
             "addAdjacentColumn16",
             "addAdjacentColumn17",
             "addAdjacentColumn18",
+            "addAdjacentColumn19",
+            "addAdjacentColumn20",
             "addAdjacentRow01",
             "addAdjacentRow02",
             "addAdjacentRow03",
@@ -1981,6 +2071,8 @@
             "addAdjacentRow16",
             "addAdjacentRow17",
             "addAdjacentRow18",
+            "addAdjacentRow19",
+            "addAdjacentRow20",
             "addColElement01",
             "addColElement02",
             "addColElement03",
@@ -2029,36 +2121,6 @@
             "deleteColumns05",
             "deleteColumns06",
             "deleteColumns07",
-            "deleteOneColumn01inside",
-            "deleteOneColumn01right",
-            "deleteOneColumn02inside",
-            "deleteOneColumn02left",
-            "deleteOneColumn02right",
-            "deleteOneColumn03inside",
-            "deleteOneColumn03left",
-            "deleteOneColumn04inside",
-            "deleteOneColumn04right",
-            "deleteOneColumn05inside",
-            "deleteOneColumn05left",
-            "deleteOneColumn05right",
-            "deleteOneColumn06inside",
-            "deleteOneColumn06left",
-            "deleteOneColumn07",
-            "deleteOneRow01below",
-            "deleteOneRow01inside",
-            "deleteOneRow02above",
-            "deleteOneRow02below",
-            "deleteOneRow02inside",
-            "deleteOneRow03above",
-            "deleteOneRow03inside",
-            "deleteOneRow04below",
-            "deleteOneRow04inside",
-            "deleteOneRow05above",
-            "deleteOneRow05below",
-            "deleteOneRow05inside",
-            "deleteOneRow06above",
-            "deleteOneRow06inside",
-            "deleteOneRow07",
             "deleteRows01",
             "deleteRows02",
             "deleteRows03",
@@ -2190,6 +2252,44 @@
             "regionSpan14",
             "regionSpan15",
             "regionSpan16",
+            "removeAdjacentColumn01inside",
+            "removeAdjacentColumn01right",
+            "removeAdjacentColumn02inside",
+            "removeAdjacentColumn02left",
+            "removeAdjacentColumn02right",
+            "removeAdjacentColumn03inside",
+            "removeAdjacentColumn03left",
+            "removeAdjacentColumn04inside",
+            "removeAdjacentColumn04right",
+            "removeAdjacentColumn05inside",
+            "removeAdjacentColumn05left",
+            "removeAdjacentColumn05right",
+            "removeAdjacentColumn06inside",
+            "removeAdjacentColumn06left",
+            "removeAdjacentColumn07",
+            "removeAdjacentColumn08",
+            "removeAdjacentColumn09",
+            "removeAdjacentColumn10",
+            "removeAdjacentColumn11",
+            "removeAdjacentRow01below",
+            "removeAdjacentRow01inside",
+            "removeAdjacentRow02above",
+            "removeAdjacentRow02below",
+            "removeAdjacentRow02inside",
+            "removeAdjacentRow03above",
+            "removeAdjacentRow03inside",
+            "removeAdjacentRow04below",
+            "removeAdjacentRow04inside",
+            "removeAdjacentRow05above",
+            "removeAdjacentRow05below",
+            "removeAdjacentRow05inside",
+            "removeAdjacentRow06above",
+            "removeAdjacentRow06inside",
+            "removeAdjacentRow07",
+            "removeAdjacentRow08",
+            "removeAdjacentRow09",
+            "removeAdjacentRow10",
+            "removeAdjacentRow11",
             "setColWidths01",
             "setColWidths02",
             "split00a",
diff --git a/Editor/tests/input/InputTests.js b/Editor/tests/input/InputTests.js
index f81a14f..d745b86 100644
--- a/Editor/tests/input/InputTests.js
+++ b/Editor/tests/input/InputTests.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function getNodeArrayText(nodes)
 {
diff --git a/Editor/tests/input/replaceRange01-expected.html b/Editor/tests/input/replaceRange01-expected.html
index dc735e2..0237441 100644
--- a/Editor/tests/input/replaceRange01-expected.html
+++ b/Editor/tests/input/replaceRange01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>SamHELLO[]xt</p></body>
+  <body>
+    <p>SamHELLO[]xt</p>
+  </body>
 </html>
diff --git a/Editor/tests/input/replaceRange02-expected.html b/Editor/tests/input/replaceRange02-expected.html
index 4d43c49..1f0ea6a 100644
--- a/Editor/tests/input/replaceRange02-expected.html
+++ b/Editor/tests/input/replaceRange02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>HELLO[]ple text</p></body>
+  <body>
+    <p>HELLO[]ple text</p>
+  </body>
 </html>
diff --git a/Editor/tests/input/replaceRange03-expected.html b/Editor/tests/input/replaceRange03-expected.html
index 48f01df..cd71d5e 100644
--- a/Editor/tests/input/replaceRange03-expected.html
+++ b/Editor/tests/input/replaceRange03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample teHELLO[]</p></body>
+  <body>
+    <p>Sample teHELLO[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/input/replaceRange05-expected.html b/Editor/tests/input/replaceRange05-expected.html
index d6433c7..7bfc8e1 100644
--- a/Editor/tests/input/replaceRange05-expected.html
+++ b/Editor/tests/input/replaceRange05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>HELLO[]Sample text</p></body>
+  <body>
+    <p>HELLO[]Sample text</p>
+  </body>
 </html>
diff --git a/Editor/tests/input/replaceRange06-expected.html b/Editor/tests/input/replaceRange06-expected.html
index 18ede2e..8df6771 100644
--- a/Editor/tests/input/replaceRange06-expected.html
+++ b/Editor/tests/input/replaceRange06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sample textHELLO[]</p></body>
+  <body>
+    <p>Sample textHELLO[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/lists/clearList08a-expected.html b/Editor/tests/lists/clearList08a-expected.html
index 60ff315..8947345 100644
--- a/Editor/tests/lists/clearList08a-expected.html
+++ b/Editor/tests/lists/clearList08a-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <ol><li><p>One</p></li></ol>
+    <ol>
+      <li><p>One</p></li>
+    </ol>
     <p>Two</p>
     <ol>
       <li><p>First</p></li>
diff --git a/Editor/tests/lists/clearList08b-expected.html b/Editor/tests/lists/clearList08b-expected.html
index 32d4756..b7946a6 100644
--- a/Editor/tests/lists/clearList08b-expected.html
+++ b/Editor/tests/lists/clearList08b-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <ol><li>One</li></ol>
+    <ol>
+      <li>One</li>
+    </ol>
     <p>Two</p>
     <ol>
       <li>First</li>
diff --git a/Editor/tests/lists/decrease-flat-tozero02a-expected.html b/Editor/tests/lists/decrease-flat-tozero02a-expected.html
index d5c80a1..d13aaf7 100644
--- a/Editor/tests/lists/decrease-flat-tozero02a-expected.html
+++ b/Editor/tests/lists/decrease-flat-tozero02a-expected.html
@@ -1,8 +1,12 @@
 <html>
   <head></head>
   <body>
-    <ol><li><p>One</p></li></ol>
+    <ol>
+      <li><p>One</p></li>
+    </ol>
     <p>[Two]</p>
-    <ol><li><p>Three</p></li></ol>
+    <ol>
+      <li><p>Three</p></li>
+    </ol>
   </body>
 </html>
diff --git a/Editor/tests/lists/decrease-flat-tozero02b-expected.html b/Editor/tests/lists/decrease-flat-tozero02b-expected.html
index a9495f7..088eaba 100644
--- a/Editor/tests/lists/decrease-flat-tozero02b-expected.html
+++ b/Editor/tests/lists/decrease-flat-tozero02b-expected.html
@@ -1,8 +1,12 @@
 <html>
   <head></head>
   <body>
-    <ol><li>One</li></ol>
+    <ol>
+      <li>One</li>
+    </ol>
     <p>[Two]</p>
-    <ol><li>Three</li></ol>
+    <ol>
+      <li>Three</li>
+    </ol>
   </body>
 </html>
diff --git a/Editor/tests/lists/decrease-nested-toone02a-expected.html b/Editor/tests/lists/decrease-nested-toone02a-expected.html
index 0ea0c47..97f4532 100644
--- a/Editor/tests/lists/decrease-nested-toone02a-expected.html
+++ b/Editor/tests/lists/decrease-nested-toone02a-expected.html
@@ -4,11 +4,15 @@
     <ol>
       <li>
         <p>One</p>
-        <ol><li><p>Two</p></li></ol>
+        <ol>
+          <li><p>Two</p></li>
+        </ol>
       </li>
       <li>
         <p>[Three]</p>
-        <ol><li><p>Four</p></li></ol>
+        <ol>
+          <li><p>Four</p></li>
+        </ol>
       </li>
       <li><p>Five</p></li>
     </ol>
diff --git a/Editor/tests/lists/decrease-nested-toone02b-expected.html b/Editor/tests/lists/decrease-nested-toone02b-expected.html
index e435755..d68fbea 100644
--- a/Editor/tests/lists/decrease-nested-toone02b-expected.html
+++ b/Editor/tests/lists/decrease-nested-toone02b-expected.html
@@ -4,11 +4,15 @@
     <ol>
       <li>
         One
-        <ol><li>Two</li></ol>
+        <ol>
+          <li>Two</li>
+        </ol>
       </li>
       <li>
         [Three]
-        <ol><li>Four</li></ol>
+        <ol>
+          <li>Four</li>
+        </ol>
       </li>
       <li>Five</li>
     </ol>
diff --git a/Editor/tests/lists/decrease-nested-toone04a-expected.html b/Editor/tests/lists/decrease-nested-toone04a-expected.html
index 532dde7..ccd7c67 100644
--- a/Editor/tests/lists/decrease-nested-toone04a-expected.html
+++ b/Editor/tests/lists/decrease-nested-toone04a-expected.html
@@ -6,7 +6,9 @@
       <li><p>[Two</p></li>
       <li>
         <p>Three]</p>
-        <ol><li><p>Four</p></li></ol>
+        <ol>
+          <li><p>Four</p></li>
+        </ol>
       </li>
       <li><p>Five</p></li>
     </ol>
diff --git a/Editor/tests/lists/decrease-nested-toone04b-expected.html b/Editor/tests/lists/decrease-nested-toone04b-expected.html
index 07663ea..3783f4a 100644
--- a/Editor/tests/lists/decrease-nested-toone04b-expected.html
+++ b/Editor/tests/lists/decrease-nested-toone04b-expected.html
@@ -6,7 +6,9 @@
       <li>[Two</li>
       <li>
         Three]
-        <ol><li>Four</li></ol>
+        <ol>
+          <li>Four</li>
+        </ol>
       </li>
       <li>Five</li>
     </ol>
diff --git a/Editor/tests/lists/decrease-nested-toone05a-expected.html b/Editor/tests/lists/decrease-nested-toone05a-expected.html
index c095fe7..2dbf1cc 100644
--- a/Editor/tests/lists/decrease-nested-toone05a-expected.html
+++ b/Editor/tests/lists/decrease-nested-toone05a-expected.html
@@ -4,7 +4,9 @@
     <ol>
       <li>
         <p>One</p>
-        <ol><li><p>Two</p></li></ol>
+        <ol>
+          <li><p>Two</p></li>
+        </ol>
       </li>
       <li><p>[Three</p></li>
       <li><p>Four]</p></li>
diff --git a/Editor/tests/lists/decrease-nested-toone05b-expected.html b/Editor/tests/lists/decrease-nested-toone05b-expected.html
index 5b7de85..916515d 100644
--- a/Editor/tests/lists/decrease-nested-toone05b-expected.html
+++ b/Editor/tests/lists/decrease-nested-toone05b-expected.html
@@ -4,7 +4,9 @@
     <ol>
       <li>
         One
-        <ol><li>Two</li></ol>
+        <ol>
+          <li>Two</li>
+        </ol>
       </li>
       <li>[Three</li>
       <li>Four]</li>
diff --git a/Editor/tests/lists/decrease-nested-tozero01a-expected.html b/Editor/tests/lists/decrease-nested-tozero01a-expected.html
index 912c2c6..c7ad61d 100644
--- a/Editor/tests/lists/decrease-nested-tozero01a-expected.html
+++ b/Editor/tests/lists/decrease-nested-tozero01a-expected.html
@@ -11,7 +11,9 @@
             <ol>
               <li>
                 <p>Four</p>
-                <ol><li><p>Five]</p></li></ol>
+                <ol>
+                  <li><p>Five]</p></li>
+                </ol>
               </li>
             </ol>
           </li>
diff --git a/Editor/tests/lists/decrease-nested-tozero01b-expected.html b/Editor/tests/lists/decrease-nested-tozero01b-expected.html
index 44f7c1a..8f70ea1 100644
--- a/Editor/tests/lists/decrease-nested-tozero01b-expected.html
+++ b/Editor/tests/lists/decrease-nested-tozero01b-expected.html
@@ -11,7 +11,9 @@
             <ol>
               <li>
                 Four
-                <ol><li>Five]</li></ol>
+                <ol>
+                  <li>Five]</li>
+                </ol>
               </li>
             </ol>
           </li>
diff --git a/Editor/tests/lists/decrease-nested-tozero02a-expected.html b/Editor/tests/lists/decrease-nested-tozero02a-expected.html
index f9dbfff..bfce678 100644
--- a/Editor/tests/lists/decrease-nested-tozero02a-expected.html
+++ b/Editor/tests/lists/decrease-nested-tozero02a-expected.html
@@ -9,7 +9,9 @@
         <ol>
           <li>
             <p>Four</p>
-            <ol><li><p>Five]</p></li></ol>
+            <ol>
+              <li><p>Five]</p></li>
+            </ol>
           </li>
         </ol>
       </li>
diff --git a/Editor/tests/lists/decrease-nested-tozero02b-expected.html b/Editor/tests/lists/decrease-nested-tozero02b-expected.html
index a52fb5f..dd2ff11 100644
--- a/Editor/tests/lists/decrease-nested-tozero02b-expected.html
+++ b/Editor/tests/lists/decrease-nested-tozero02b-expected.html
@@ -9,7 +9,9 @@
         <ol>
           <li>
             Four
-            <ol><li>Five]</li></ol>
+            <ol>
+              <li>Five]</li>
+            </ol>
           </li>
         </ol>
       </li>
diff --git a/Editor/tests/lists/decrease-nested-tozero03a-expected.html b/Editor/tests/lists/decrease-nested-tozero03a-expected.html
index 787e44a..6ff3a1b 100644
--- a/Editor/tests/lists/decrease-nested-tozero03a-expected.html
+++ b/Editor/tests/lists/decrease-nested-tozero03a-expected.html
@@ -7,7 +7,9 @@
     <ol>
       <li>
         <p>Four</p>
-        <ol><li><p>Five]</p></li></ol>
+        <ol>
+          <li><p>Five]</p></li>
+        </ol>
       </li>
     </ol>
   </body>
diff --git a/Editor/tests/lists/decrease-nested-tozero03b-expected.html b/Editor/tests/lists/decrease-nested-tozero03b-expected.html
index c7ca17f..377d3aa 100644
--- a/Editor/tests/lists/decrease-nested-tozero03b-expected.html
+++ b/Editor/tests/lists/decrease-nested-tozero03b-expected.html
@@ -7,7 +7,9 @@
     <ol>
       <li>
         Four
-        <ol><li>Five]</li></ol>
+        <ol>
+          <li>Five]</li>
+        </ol>
       </li>
     </ol>
   </body>
diff --git a/Editor/tests/lists/decrease-nested-tozero04a-expected.html b/Editor/tests/lists/decrease-nested-tozero04a-expected.html
index 3a2f690..e44a924 100644
--- a/Editor/tests/lists/decrease-nested-tozero04a-expected.html
+++ b/Editor/tests/lists/decrease-nested-tozero04a-expected.html
@@ -5,6 +5,8 @@
     <p>Two</p>
     <p>Three</p>
     <p>Four</p>
-    <ol><li><p>Five]</p></li></ol>
+    <ol>
+      <li><p>Five]</p></li>
+    </ol>
   </body>
 </html>
diff --git a/Editor/tests/lists/decrease-nested-tozero04b-expected.html b/Editor/tests/lists/decrease-nested-tozero04b-expected.html
index 83b0303..7b4c5e1 100644
--- a/Editor/tests/lists/decrease-nested-tozero04b-expected.html
+++ b/Editor/tests/lists/decrease-nested-tozero04b-expected.html
@@ -5,6 +5,8 @@
     <p>Two</p>
     <p>Three</p>
     <p>Four</p>
-    <ol><li>Five]</li></ol>
+    <ol>
+      <li>Five]</li>
+    </ol>
   </body>
 </html>
diff --git a/Editor/tests/lists/div01a-expected.html b/Editor/tests/lists/div01a-expected.html
index a4af1eb..3f37489 100644
--- a/Editor/tests/lists/div01a-expected.html
+++ b/Editor/tests/lists/div01a-expected.html
@@ -3,7 +3,9 @@
   <body>
     <div>
       <p>One</p>
-      <ol><li><p>Two[]</p></li></ol>
+      <ol>
+        <li><p>Two[]</p></li>
+      </ol>
       <p>Three</p>
     </div>
   </body>
diff --git a/Editor/tests/lists/div02a-expected.html b/Editor/tests/lists/div02a-expected.html
index b817032..dc94c9f 100644
--- a/Editor/tests/lists/div02a-expected.html
+++ b/Editor/tests/lists/div02a-expected.html
@@ -2,9 +2,13 @@
   <head></head>
   <body>
     <div>
-      <ul><li><p>One</p></li></ul>
+      <ul>
+        <li><p>One</p></li>
+      </ul>
       <p>Two[]</p>
-      <ul><li><p>Three</p></li></ul>
+      <ul>
+        <li><p>Three</p></li>
+      </ul>
     </div>
   </body>
 </html>
diff --git a/Editor/tests/lists/div03a-expected.html b/Editor/tests/lists/div03a-expected.html
index e026d5a..84a1a82 100644
--- a/Editor/tests/lists/div03a-expected.html
+++ b/Editor/tests/lists/div03a-expected.html
@@ -2,9 +2,13 @@
   <head></head>
   <body>
     <div>
-      <ul><li>One</li></ul>
+      <ul>
+        <li>One</li>
+      </ul>
       <p>Two[]</p>
-      <ul><li>Three</li></ul>
+      <ul>
+        <li>Three</li>
+      </ul>
     </div>
   </body>
 </html>
diff --git a/Editor/tests/lists/increase-flat02a-expected.html b/Editor/tests/lists/increase-flat02a-expected.html
index f3a2bd4..3515f4b 100644
--- a/Editor/tests/lists/increase-flat02a-expected.html
+++ b/Editor/tests/lists/increase-flat02a-expected.html
@@ -4,7 +4,9 @@
     <ol>
       <li>
         <p>One</p>
-        <ol><li><p>[Two]</p></li></ol>
+        <ol>
+          <li><p>[Two]</p></li>
+        </ol>
       </li>
       <li><p>Three</p></li>
     </ol>
diff --git a/Editor/tests/lists/increase-flat02b-expected.html b/Editor/tests/lists/increase-flat02b-expected.html
index 8013f97..7b82edc 100644
--- a/Editor/tests/lists/increase-flat02b-expected.html
+++ b/Editor/tests/lists/increase-flat02b-expected.html
@@ -4,7 +4,9 @@
     <ol>
       <li>
         One
-        <ol><li>[Two]</li></ol>
+        <ol>
+          <li>[Two]</li>
+        </ol>
       </li>
       <li>Three</li>
     </ol>
diff --git a/Editor/tests/lists/increase-flat03a-expected.html b/Editor/tests/lists/increase-flat03a-expected.html
index 0032786..3ed43b3 100644
--- a/Editor/tests/lists/increase-flat03a-expected.html
+++ b/Editor/tests/lists/increase-flat03a-expected.html
@@ -5,7 +5,9 @@
       <li><p>One</p></li>
       <li>
         <p>Two</p>
-        <ol><li><p>[Three]</p></li></ol>
+        <ol>
+          <li><p>[Three]</p></li>
+        </ol>
       </li>
     </ol>
   </body>
diff --git a/Editor/tests/lists/increase-flat03b-expected.html b/Editor/tests/lists/increase-flat03b-expected.html
index dd054ba..7b3c432 100644
--- a/Editor/tests/lists/increase-flat03b-expected.html
+++ b/Editor/tests/lists/increase-flat03b-expected.html
@@ -5,7 +5,9 @@
       <li>One</li>
       <li>
         Two
-        <ol><li>[Three]</li></ol>
+        <ol>
+          <li>[Three]</li>
+        </ol>
       </li>
     </ol>
   </body>
diff --git a/Editor/tests/lists/increase-misc01a-expected.html b/Editor/tests/lists/increase-misc01a-expected.html
index 28f08ac..69f9c96 100644
--- a/Editor/tests/lists/increase-misc01a-expected.html
+++ b/Editor/tests/lists/increase-misc01a-expected.html
@@ -5,7 +5,9 @@
       <li><p>One</p></li>
       <li>
         <p>Two</p>
-        <ol><li><p>[]</p></li></ol>
+        <ol>
+          <li><p>[]</p></li>
+        </ol>
       </li>
     </ol>
   </body>
diff --git a/Editor/tests/lists/increase-misc01b-expected.html b/Editor/tests/lists/increase-misc01b-expected.html
index 142abcd..c743f35 100644
--- a/Editor/tests/lists/increase-misc01b-expected.html
+++ b/Editor/tests/lists/increase-misc01b-expected.html
@@ -5,7 +5,9 @@
       <li>One</li>
       <li>
         Two
-        <ol><li>[]</li></ol>
+        <ol>
+          <li>[]</li>
+        </ol>
       </li>
     </ol>
   </body>
diff --git a/Editor/tests/lists/increase-misc02a-expected.html b/Editor/tests/lists/increase-misc02a-expected.html
index 5c7431a..63e1c40 100644
--- a/Editor/tests/lists/increase-misc02a-expected.html
+++ b/Editor/tests/lists/increase-misc02a-expected.html
@@ -5,7 +5,9 @@
       <li><p>One</p></li>
       <li>
         <p>Two</p>
-        <ol><li><p id="test">[]</p></li></ol>
+        <ol>
+          <li><p id="test">[]</p></li>
+        </ol>
       </li>
     </ol>
   </body>
diff --git a/Editor/tests/lists/increase-misc02b-expected.html b/Editor/tests/lists/increase-misc02b-expected.html
index 6cec2b1..ec81c0c 100644
--- a/Editor/tests/lists/increase-misc02b-expected.html
+++ b/Editor/tests/lists/increase-misc02b-expected.html
@@ -5,7 +5,9 @@
       <li>One</li>
       <li>
         Two
-        <ol><li id="test">[]</li></ol>
+        <ol>
+          <li id="test">[]</li>
+        </ol>
       </li>
     </ol>
   </body>
diff --git a/Editor/tests/lists/increase-misc03a-expected.html b/Editor/tests/lists/increase-misc03a-expected.html
index 9796075..51cb507 100644
--- a/Editor/tests/lists/increase-misc03a-expected.html
+++ b/Editor/tests/lists/increase-misc03a-expected.html
@@ -4,7 +4,9 @@
     <ol>
       <li>
         One
-        <ol><li>[]</li></ol>
+        <ol>
+          <li>[]</li>
+        </ol>
       </li>
     </ol>
   </body>
diff --git a/Editor/tests/lists/increase-multiple02a-expected.html b/Editor/tests/lists/increase-multiple02a-expected.html
index a30c863..c51b85e 100644
--- a/Editor/tests/lists/increase-multiple02a-expected.html
+++ b/Editor/tests/lists/increase-multiple02a-expected.html
@@ -13,7 +13,9 @@
                 <ol>
                   <li>
                     <p>Four</p>
-                    <ol><li><p>Five]</p></li></ol>
+                    <ol>
+                      <li><p>Five]</p></li>
+                    </ol>
                   </li>
                 </ol>
               </li>
diff --git a/Editor/tests/lists/increase-multiple02b-expected.html b/Editor/tests/lists/increase-multiple02b-expected.html
index 20bb4e2..589b47f 100644
--- a/Editor/tests/lists/increase-multiple02b-expected.html
+++ b/Editor/tests/lists/increase-multiple02b-expected.html
@@ -13,7 +13,9 @@
                 <ol>
                   <li>
                     Four
-                    <ol><li>Five]</li></ol>
+                    <ol>
+                      <li>Five]</li>
+                    </ol>
                   </li>
                 </ol>
               </li>
diff --git a/Editor/tests/lists/merge03a-expected.html b/Editor/tests/lists/merge03a-expected.html
index 4392139..906f4e8 100644
--- a/Editor/tests/lists/merge03a-expected.html
+++ b/Editor/tests/lists/merge03a-expected.html
@@ -5,9 +5,15 @@
       <li><p>One</p></li>
       <li><p>Two</p></li>
     </ul>
-    <ol><li><p>Three</p></li></ol>
-    <ul><li><p>Four</p></li></ul>
-    <ol><li><p>Five</p></li></ol>
+    <ol>
+      <li><p>Three</p></li>
+    </ol>
+    <ul>
+      <li><p>Four</p></li>
+    </ul>
+    <ol>
+      <li><p>Five</p></li>
+    </ol>
     <ul>
       <li><p>Six</p></li>
       <li><p>Seven</p></li>
diff --git a/Editor/tests/lists/merge03b-expected.html b/Editor/tests/lists/merge03b-expected.html
index d63bb9a..1d2c048 100644
--- a/Editor/tests/lists/merge03b-expected.html
+++ b/Editor/tests/lists/merge03b-expected.html
@@ -5,9 +5,15 @@
       <li>One</li>
       <li>Two</li>
     </ul>
-    <ol><li>Three</li></ol>
-    <ul><li>Four</li></ul>
-    <ol><li>Five</li></ol>
+    <ol>
+      <li>Three</li>
+    </ol>
+    <ul>
+      <li>Four</li>
+    </ul>
+    <ol>
+      <li>Five</li>
+    </ol>
     <ul>
       <li>Six</li>
       <li>Seven</li>
diff --git a/Editor/tests/lists/ol-from-ul02a-expected.html b/Editor/tests/lists/ol-from-ul02a-expected.html
index 85805d9..29f51f8 100644
--- a/Editor/tests/lists/ol-from-ul02a-expected.html
+++ b/Editor/tests/lists/ol-from-ul02a-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <ol><li><p>One</p></li></ol>
+    <ol>
+      <li><p>One</p></li>
+    </ol>
     <ul>
       <li><p>Two</p></li>
       <li><p>Three</p></li>
diff --git a/Editor/tests/lists/ol-from-ul02b-expected.html b/Editor/tests/lists/ol-from-ul02b-expected.html
index 37040c4..55be2e0 100644
--- a/Editor/tests/lists/ol-from-ul02b-expected.html
+++ b/Editor/tests/lists/ol-from-ul02b-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <ol><li>One</li></ol>
+    <ol>
+      <li>One</li>
+    </ol>
     <ul>
       <li>Two</li>
       <li>Three</li>
diff --git a/Editor/tests/lists/ol-from-ul03a-expected.html b/Editor/tests/lists/ol-from-ul03a-expected.html
index 3f7390e..780a1f7 100644
--- a/Editor/tests/lists/ol-from-ul03a-expected.html
+++ b/Editor/tests/lists/ol-from-ul03a-expected.html
@@ -5,7 +5,9 @@
       <li><p>One</p></li>
       <li><p>Two</p></li>
     </ul>
-    <ol><li><p>Three</p></li></ol>
+    <ol>
+      <li><p>Three</p></li>
+    </ol>
     <ul>
       <li><p>Four</p></li>
       <li><p>Five</p></li>
diff --git a/Editor/tests/lists/ol-from-ul03b-expected.html b/Editor/tests/lists/ol-from-ul03b-expected.html
index 87968a5..e957e61 100644
--- a/Editor/tests/lists/ol-from-ul03b-expected.html
+++ b/Editor/tests/lists/ol-from-ul03b-expected.html
@@ -5,7 +5,9 @@
       <li>One</li>
       <li>Two</li>
     </ul>
-    <ol><li>Three</li></ol>
+    <ol>
+      <li>Three</li>
+    </ol>
     <ul>
       <li>Four</li>
       <li>Five</li>
diff --git a/Editor/tests/lists/ol-from-ul04a-expected.html b/Editor/tests/lists/ol-from-ul04a-expected.html
index 82362f1..4f4f65e 100644
--- a/Editor/tests/lists/ol-from-ul04a-expected.html
+++ b/Editor/tests/lists/ol-from-ul04a-expected.html
@@ -7,6 +7,8 @@
       <li><p>Three</p></li>
       <li><p>Four</p></li>
     </ul>
-    <ol><li><p>Five</p></li></ol>
+    <ol>
+      <li><p>Five</p></li>
+    </ol>
   </body>
 </html>
\ No newline at end of file
diff --git a/Editor/tests/lists/ol-from-ul04b-expected.html b/Editor/tests/lists/ol-from-ul04b-expected.html
index edb66fb..02bef3d 100644
--- a/Editor/tests/lists/ol-from-ul04b-expected.html
+++ b/Editor/tests/lists/ol-from-ul04b-expected.html
@@ -7,6 +7,8 @@
       <li>Three</li>
       <li>Four</li>
     </ul>
-    <ol><li>Five</li></ol>
+    <ol>
+      <li>Five</li>
+    </ol>
   </body>
 </html>
\ No newline at end of file
diff --git a/Editor/tests/lists/ol-from-ul07a-expected.html b/Editor/tests/lists/ol-from-ul07a-expected.html
index 5e5cbb7..af0faed 100644
--- a/Editor/tests/lists/ol-from-ul07a-expected.html
+++ b/Editor/tests/lists/ol-from-ul07a-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <ul><li><p>One</p></li></ul>
+    <ul>
+      <li><p>One</p></li>
+    </ul>
     <ol>
       <li>
         <p>Two</p>
diff --git a/Editor/tests/lists/ol-from-ul07b-expected.html b/Editor/tests/lists/ol-from-ul07b-expected.html
index f508437..28dd3d2 100644
--- a/Editor/tests/lists/ol-from-ul07b-expected.html
+++ b/Editor/tests/lists/ol-from-ul07b-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <ul><li>One</li></ul>
+    <ul>
+      <li>One</li>
+    </ul>
     <ol>
       <li>
         Two
diff --git a/Editor/tests/lists/ol02-expected.html b/Editor/tests/lists/ol02-expected.html
index 3964d67..3bde522 100644
--- a/Editor/tests/lists/ol02-expected.html
+++ b/Editor/tests/lists/ol02-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <ol><li><p>One</p></li></ol>
+    <ol>
+      <li><p>One</p></li>
+    </ol>
     <p>Two</p>
     <p>Three</p>
     <p>Four</p>
diff --git a/Editor/tests/lists/ol03-expected.html b/Editor/tests/lists/ol03-expected.html
index 9ebc843..de420ba 100644
--- a/Editor/tests/lists/ol03-expected.html
+++ b/Editor/tests/lists/ol03-expected.html
@@ -3,7 +3,9 @@
   <body>
     <p>One</p>
     <p>Two</p>
-    <ol><li><p>Three</p></li></ol>
+    <ol>
+      <li><p>Three</p></li>
+    </ol>
     <p>Four</p>
     <p>Five</p>
   </body>
diff --git a/Editor/tests/lists/ol04-expected.html b/Editor/tests/lists/ol04-expected.html
index ff39662..fd4d870 100644
--- a/Editor/tests/lists/ol04-expected.html
+++ b/Editor/tests/lists/ol04-expected.html
@@ -5,6 +5,8 @@
     <p>Two</p>
     <p>Three</p>
     <p>Four</p>
-    <ol><li><p>Five</p></li></ol>
+    <ol>
+      <li><p>Five</p></li>
+    </ol>
   </body>
 </html>
\ No newline at end of file
diff --git a/Editor/tests/lists/setList-headings01-expected.html b/Editor/tests/lists/setList-headings01-expected.html
index 98e1748..57a648a 100644
--- a/Editor/tests/lists/setList-headings01-expected.html
+++ b/Editor/tests/lists/setList-headings01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1 id="item1">[Test]</h1></body>
+  <body>
+    <h1 id="item1">[Test]</h1>
+  </body>
 </html>
diff --git a/Editor/tests/lists/setList-headings03-expected.html b/Editor/tests/lists/setList-headings03-expected.html
index 516bacd..7a9cd9d 100644
--- a/Editor/tests/lists/setList-headings03-expected.html
+++ b/Editor/tests/lists/setList-headings03-expected.html
@@ -1,8 +1,12 @@
 <html>
   <head></head>
   <body>
-    <ul><li><p>[One</p></li></ul>
+    <ul>
+      <li><p>[One</p></li>
+    </ul>
     <h1 id="item1">Two</h1>
-    <ul><li><p>Three]</p></li></ul>
+    <ul>
+      <li><p>Three]</p></li>
+    </ul>
   </body>
 </html>
diff --git a/Editor/tests/lists/setList-innerp02-expected.html b/Editor/tests/lists/setList-innerp02-expected.html
index 2cceaea..3a20361 100644
--- a/Editor/tests/lists/setList-innerp02-expected.html
+++ b/Editor/tests/lists/setList-innerp02-expected.html
@@ -4,7 +4,9 @@
     <ul>
       <li>
         <p>One</p>
-        <ul><li><p>[]Two</p></li></ul>
+        <ul>
+          <li><p>[]Two</p></li>
+        </ul>
       </li>
     </ul>
   </body>
diff --git a/Editor/tests/lists/setList-innerp04-expected.html b/Editor/tests/lists/setList-innerp04-expected.html
index 96db813..d0fe455 100644
--- a/Editor/tests/lists/setList-innerp04-expected.html
+++ b/Editor/tests/lists/setList-innerp04-expected.html
@@ -9,7 +9,9 @@
           <li><p>Three</p></li>
           <li><p>Four</p></li>
         </ul>
-        <ol><li><p>[]Five</p></li></ol>
+        <ol>
+          <li><p>[]Five</p></li>
+        </ol>
       </li>
       <li><p>Six</p></li>
     </ul>
diff --git a/Editor/tests/lists/setList-nested07-expected.html b/Editor/tests/lists/setList-nested07-expected.html
index 77a3585..5caabe9 100644
--- a/Editor/tests/lists/setList-nested07-expected.html
+++ b/Editor/tests/lists/setList-nested07-expected.html
@@ -17,6 +17,8 @@
       <li><p>Seven</p></li>
       <li><p>Eigh]t</p></li>
     </ol>
-    <ul><li><p>Nine</p></li></ul>
+    <ul>
+      <li><p>Nine</p></li>
+    </ul>
   </body>
 </html>
diff --git a/Editor/tests/lists/setList-nested08-expected.html b/Editor/tests/lists/setList-nested08-expected.html
index 9dea7ca..23e238e 100644
--- a/Editor/tests/lists/setList-nested08-expected.html
+++ b/Editor/tests/lists/setList-nested08-expected.html
@@ -16,6 +16,8 @@
       <li><p>Seven</p></li>
       <li><p>Eigh]t</p></li>
     </ol>
-    <ul><li><p>Nine</p></li></ul>
+    <ul>
+      <li><p>Nine</p></li>
+    </ul>
   </body>
 </html>
diff --git a/Editor/tests/lists/setList-nop01-expected.html b/Editor/tests/lists/setList-nop01-expected.html
index 90128c8..f032705 100644
--- a/Editor/tests/lists/setList-nop01-expected.html
+++ b/Editor/tests/lists/setList-nop01-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li>[test]</li></ul></body>
+  <body>
+    <ul>
+      <li>[test]</li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/lists/setList-nop02-expected.html b/Editor/tests/lists/setList-nop02-expected.html
index 8718df2..1e26a12 100644
--- a/Editor/tests/lists/setList-nop02-expected.html
+++ b/Editor/tests/lists/setList-nop02-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li>[]</li></ul></body>
+  <body>
+    <ul>
+      <li>[]</li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/lists/setList-nop03-expected.html b/Editor/tests/lists/setList-nop03-expected.html
index b80d230..23649c7 100644
--- a/Editor/tests/lists/setList-nop03-expected.html
+++ b/Editor/tests/lists/setList-nop03-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li>test[]</li></ul></body>
+  <body>
+    <ul>
+      <li>test[]</li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/lists/setList-nop04-expected.html b/Editor/tests/lists/setList-nop04-expected.html
index 55131c4..c43e793 100644
--- a/Editor/tests/lists/setList-nop04-expected.html
+++ b/Editor/tests/lists/setList-nop04-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li>[]test</li></ul></body>
+  <body>
+    <ul>
+      <li>[]test</li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/lists/setList-nop05-expected.html b/Editor/tests/lists/setList-nop05-expected.html
index 8718df2..1e26a12 100644
--- a/Editor/tests/lists/setList-nop05-expected.html
+++ b/Editor/tests/lists/setList-nop05-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li>[]</li></ul></body>
+  <body>
+    <ul>
+      <li>[]</li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/lists/setList-paragraphs05-expected.html b/Editor/tests/lists/setList-paragraphs05-expected.html
index 3bd1904..8172759 100644
--- a/Editor/tests/lists/setList-paragraphs05-expected.html
+++ b/Editor/tests/lists/setList-paragraphs05-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li><p>[]</p></li></ul></body>
+  <body>
+    <ul>
+      <li><p>[]</p></li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/lists/setList-paragraphs06-expected.html b/Editor/tests/lists/setList-paragraphs06-expected.html
index 4167390..b4060bf 100644
--- a/Editor/tests/lists/setList-paragraphs06-expected.html
+++ b/Editor/tests/lists/setList-paragraphs06-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li><p>test[]</p></li></ul></body>
+  <body>
+    <ul>
+      <li><p>test[]</p></li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/lists/setList-paragraphs07-expected.html b/Editor/tests/lists/setList-paragraphs07-expected.html
index e599090..548fbfe 100644
--- a/Editor/tests/lists/setList-paragraphs07-expected.html
+++ b/Editor/tests/lists/setList-paragraphs07-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li><p>[]test</p></li></ul></body>
+  <body>
+    <ul>
+      <li><p>[]test</p></li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/lists/ul02-expected.html b/Editor/tests/lists/ul02-expected.html
index b390081..f8fdae0 100644
--- a/Editor/tests/lists/ul02-expected.html
+++ b/Editor/tests/lists/ul02-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <ul><li><p>One</p></li></ul>
+    <ul>
+      <li><p>One</p></li>
+    </ul>
     <p>Two</p>
     <p>Three</p>
     <p>Four</p>
diff --git a/Editor/tests/lists/ul03-expected.html b/Editor/tests/lists/ul03-expected.html
index 7f7bfcd..230709c 100644
--- a/Editor/tests/lists/ul03-expected.html
+++ b/Editor/tests/lists/ul03-expected.html
@@ -3,7 +3,9 @@
   <body>
     <p>One</p>
     <p>Two</p>
-    <ul><li><p>Three</p></li></ul>
+    <ul>
+      <li><p>Three</p></li>
+    </ul>
     <p>Four</p>
     <p>Five</p>
   </body>
diff --git a/Editor/tests/lists/ul04-expected.html b/Editor/tests/lists/ul04-expected.html
index 40bd0f4..0c28fc6 100644
--- a/Editor/tests/lists/ul04-expected.html
+++ b/Editor/tests/lists/ul04-expected.html
@@ -5,6 +5,8 @@
     <p>Two</p>
     <p>Three</p>
     <p>Four</p>
-    <ul><li><p>Five</p></li></ul>
+    <ul>
+      <li><p>Five</p></li>
+    </ul>
   </body>
 </html>
\ No newline at end of file
diff --git a/Editor/tests/main/removeSpecial02-expected.html b/Editor/tests/main/removeSpecial02-expected.html
index cdf9e3c..15d8615 100644
--- a/Editor/tests/main/removeSpecial02-expected.html
+++ b/Editor/tests/main/removeSpecial02-expected.html
@@ -3,7 +3,9 @@
 
 <html>
   <head></head>
-  <body><p><span class="uxwrite-selection">one two three</span></p></body>
+  <body>
+    <p><span class="uxwrite-selection">one two three</span></p>
+  </body>
 </html>
 
 After
@@ -11,5 +13,7 @@
 
 <html>
   <head></head>
-  <body><p>one two three</p></body>
+  <body>
+    <p>one two three</p>
+  </body>
 </html>
diff --git a/Editor/tests/outline/OutlineTest.js b/Editor/tests/outline/OutlineTest.js
index 130b5c1..587e82c 100644
--- a/Editor/tests/outline/OutlineTest.js
+++ b/Editor/tests/outline/OutlineTest.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function createTestSections(topChildren)
 {
diff --git a/Editor/tests/outline/changeHeadingToParagraph-expected.html b/Editor/tests/outline/changeHeadingToParagraph-expected.html
index 69eff63..f9b3d80 100644
--- a/Editor/tests/outline/changeHeadingToParagraph-expected.html
+++ b/Editor/tests/outline/changeHeadingToParagraph-expected.html
@@ -4,7 +4,9 @@
     </style>
   </head>
   <body>
-    <nav class="tableofcontents"><p class="toc1">[No sections defined]</p></nav>
+    <nav class="tableofcontents">
+      <p class="toc1">[No sections defined]</p>
+    </nav>
     <p>Heading</p>
   </body>
 </html>
diff --git a/Editor/tests/outline/discovery02-expected.html b/Editor/tests/outline/discovery02-expected.html
index 2e9ec0d..dcb2a30 100644
--- a/Editor/tests/outline/discovery02-expected.html
+++ b/Editor/tests/outline/discovery02-expected.html
@@ -17,13 +17,25 @@
   </head>
   <body>
     <h1 id="item1">First heading</h1>
-    <figure id="item2"><figcaption/></figure>
-    <table id="item3"><caption/></table>
+    <figure id="item2">
+      <figcaption/>
+    </figure>
+    <table id="item3">
+      <caption/>
+    </table>
     <h2 id="item4">Second heading</h2>
-    <figure id="item5"><figcaption/></figure>
-    <table id="item6"><caption/></table>
+    <figure id="item5">
+      <figcaption/>
+    </figure>
+    <table id="item6">
+      <caption/>
+    </table>
     <h3 id="item7">Third heading</h3>
-    <figure id="item8"><figcaption/></figure>
-    <table id="item9"><caption/></table>
+    <figure id="item8">
+      <figcaption/>
+    </figure>
+    <table id="item9">
+      <caption/>
+    </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/discovery03-expected.html b/Editor/tests/outline/discovery03-expected.html
index cb9e66f..dae801d 100644
--- a/Editor/tests/outline/discovery03-expected.html
+++ b/Editor/tests/outline/discovery03-expected.html
@@ -15,13 +15,25 @@
   </head>
   <body>
     <h1 id="item1">First section</h1>
-    <figure id="item2"><figcaption class="Unnumbered">First figure</figcaption></figure>
-    <table id="item3"><caption class="Unnumbered">First table</caption></table>
+    <figure id="item2">
+      <figcaption class="Unnumbered">First figure</figcaption>
+    </figure>
+    <table id="item3">
+      <caption class="Unnumbered">First table</caption>
+    </table>
     <h1 id="item4">Second section</h1>
-    <figure id="item5"><figcaption class="Unnumbered">Second figure</figcaption></figure>
-    <table id="item6"><caption class="Unnumbered">Second table</caption></table>
+    <figure id="item5">
+      <figcaption class="Unnumbered">Second figure</figcaption>
+    </figure>
+    <table id="item6">
+      <caption class="Unnumbered">Second table</caption>
+    </table>
     <h1 id="item7">Third section</h1>
-    <figure id="item8"><figcaption class="Unnumbered">Third figure</figcaption></figure>
-    <table id="item9"><caption class="Unnumbered">Third table</caption></table>
+    <figure id="item8">
+      <figcaption class="Unnumbered">Third figure</figcaption>
+    </figure>
+    <table id="item9">
+      <caption class="Unnumbered">Third table</caption>
+    </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/discovery04-expected.html b/Editor/tests/outline/discovery04-expected.html
index 28a8f9f..09986e2 100644
--- a/Editor/tests/outline/discovery04-expected.html
+++ b/Editor/tests/outline/discovery04-expected.html
@@ -17,13 +17,25 @@
   </head>
   <body>
     <h1 id="item1">First section</h1>
-    <figure id="item2"><figcaption>First figure</figcaption></figure>
-    <table id="item3"><caption>First table</caption></table>
+    <figure id="item2">
+      <figcaption>First figure</figcaption>
+    </figure>
+    <table id="item3">
+      <caption>First table</caption>
+    </table>
     <h1 id="item4">Second section</h1>
-    <figure id="item5"><figcaption>Second figure</figcaption></figure>
-    <table id="item6"><caption>Second table</caption></table>
+    <figure id="item5">
+      <figcaption>Second figure</figcaption>
+    </figure>
+    <table id="item6">
+      <caption>Second table</caption>
+    </table>
     <h1 id="item7">Third section</h1>
-    <figure id="item8"><figcaption>Third figure</figcaption></figure>
-    <table id="item9"><caption>Third table</caption></table>
+    <figure id="item8">
+      <figcaption>Third figure</figcaption>
+    </figure>
+    <table id="item9">
+      <caption>Third table</caption>
+    </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/discovery05-expected.html b/Editor/tests/outline/discovery05-expected.html
index 28a8f9f..09986e2 100644
--- a/Editor/tests/outline/discovery05-expected.html
+++ b/Editor/tests/outline/discovery05-expected.html
@@ -17,13 +17,25 @@
   </head>
   <body>
     <h1 id="item1">First section</h1>
-    <figure id="item2"><figcaption>First figure</figcaption></figure>
-    <table id="item3"><caption>First table</caption></table>
+    <figure id="item2">
+      <figcaption>First figure</figcaption>
+    </figure>
+    <table id="item3">
+      <caption>First table</caption>
+    </table>
     <h1 id="item4">Second section</h1>
-    <figure id="item5"><figcaption>Second figure</figcaption></figure>
-    <table id="item6"><caption>Second table</caption></table>
+    <figure id="item5">
+      <figcaption>Second figure</figcaption>
+    </figure>
+    <table id="item6">
+      <caption>Second table</caption>
+    </table>
     <h1 id="item7">Third section</h1>
-    <figure id="item8"><figcaption>Third figure</figcaption></figure>
-    <table id="item9"><caption>Third table</caption></table>
+    <figure id="item8">
+      <figcaption>Third figure</figcaption>
+    </figure>
+    <table id="item9">
+      <caption>Third table</caption>
+    </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/discovery06-expected.html b/Editor/tests/outline/discovery06-expected.html
index adb404f..3f65556 100644
--- a/Editor/tests/outline/discovery06-expected.html
+++ b/Editor/tests/outline/discovery06-expected.html
@@ -17,13 +17,25 @@
   </head>
   <body>
     <h1 class="Unnumbered" id="item1">First section</h1>
-    <figure id="item2"><figcaption class="Unnumbered">First figure</figcaption></figure>
-    <table id="item3"><caption class="Unnumbered">First table</caption></table>
+    <figure id="item2">
+      <figcaption class="Unnumbered">First figure</figcaption>
+    </figure>
+    <table id="item3">
+      <caption class="Unnumbered">First table</caption>
+    </table>
     <h1 class="Unnumbered" id="item4">Second section</h1>
-    <figure id="item5"><figcaption class="Unnumbered">Second figure</figcaption></figure>
-    <table id="item6"><caption class="Unnumbered">Second table</caption></table>
+    <figure id="item5">
+      <figcaption class="Unnumbered">Second figure</figcaption>
+    </figure>
+    <table id="item6">
+      <caption class="Unnumbered">Second table</caption>
+    </table>
     <h1 class="Unnumbered" id="item7">Third section</h1>
-    <figure id="item8"><figcaption class="Unnumbered">Third figure</figcaption></figure>
-    <table id="item9"><caption class="Unnumbered">Third table</caption></table>
+    <figure id="item8">
+      <figcaption class="Unnumbered">Third figure</figcaption>
+    </figure>
+    <table id="item9">
+      <caption class="Unnumbered">Third table</caption>
+    </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/discovery07-expected.html b/Editor/tests/outline/discovery07-expected.html
index adb404f..3f65556 100644
--- a/Editor/tests/outline/discovery07-expected.html
+++ b/Editor/tests/outline/discovery07-expected.html
@@ -17,13 +17,25 @@
   </head>
   <body>
     <h1 class="Unnumbered" id="item1">First section</h1>
-    <figure id="item2"><figcaption class="Unnumbered">First figure</figcaption></figure>
-    <table id="item3"><caption class="Unnumbered">First table</caption></table>
+    <figure id="item2">
+      <figcaption class="Unnumbered">First figure</figcaption>
+    </figure>
+    <table id="item3">
+      <caption class="Unnumbered">First table</caption>
+    </table>
     <h1 class="Unnumbered" id="item4">Second section</h1>
-    <figure id="item5"><figcaption class="Unnumbered">Second figure</figcaption></figure>
-    <table id="item6"><caption class="Unnumbered">Second table</caption></table>
+    <figure id="item5">
+      <figcaption class="Unnumbered">Second figure</figcaption>
+    </figure>
+    <table id="item6">
+      <caption class="Unnumbered">Second table</caption>
+    </table>
     <h1 class="Unnumbered" id="item7">Third section</h1>
-    <figure id="item8"><figcaption class="Unnumbered">Third figure</figcaption></figure>
-    <table id="item9"><caption class="Unnumbered">Third table</caption></table>
+    <figure id="item8">
+      <figcaption class="Unnumbered">Third figure</figcaption>
+    </figure>
+    <table id="item9">
+      <caption class="Unnumbered">Third table</caption>
+    </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/heading-editing04-expected.html b/Editor/tests/outline/heading-editing04-expected.html
index 909decd..25e101b 100644
--- a/Editor/tests/outline/heading-editing04-expected.html
+++ b/Editor/tests/outline/heading-editing04-expected.html
@@ -4,7 +4,9 @@
     </style>
   </head>
   <body>
-    <nav class="tableofcontents"><p class="toc1">[No sections defined]</p></nav>
+    <nav class="tableofcontents">
+      <p class="toc1">[No sections defined]</p>
+    </nav>
     <p>Texter</p>
   </body>
 </html>
diff --git a/Editor/tests/outline/heading-editing05-expected.html b/Editor/tests/outline/heading-editing05-expected.html
index 53122e5..b01af02 100644
--- a/Editor/tests/outline/heading-editing05-expected.html
+++ b/Editor/tests/outline/heading-editing05-expected.html
@@ -4,7 +4,9 @@
     </style>
   </head>
   <body>
-    <nav class="tableofcontents"><p class="toc1">[No sections defined]</p></nav>
+    <nav class="tableofcontents">
+      <p class="toc1">[No sections defined]</p>
+    </nav>
     <p>Texer</p>
   </body>
 </html>
diff --git a/Editor/tests/outline/heading-editing07-expected.html b/Editor/tests/outline/heading-editing07-expected.html
index 7e1a033..616c3c5 100644
--- a/Editor/tests/outline/heading-editing07-expected.html
+++ b/Editor/tests/outline/heading-editing07-expected.html
@@ -4,7 +4,9 @@
     </style>
   </head>
   <body>
-    <nav class="tableofcontents"><p class="toc1"><a href="#item1">1</a></p></nav>
+    <nav class="tableofcontents">
+      <p class="toc1"><a href="#item1">1</a></p>
+    </nav>
     <h1 id="item1"><br/></h1>
   </body>
 </html>
diff --git a/Editor/tests/outline/heading-hierarchy03a-expected.html b/Editor/tests/outline/heading-hierarchy03a-expected.html
index aa81985..5efc7d6 100644
--- a/Editor/tests/outline/heading-hierarchy03a-expected.html
+++ b/Editor/tests/outline/heading-hierarchy03a-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <ol><li><p>One</p></li></ol>
+    <ol>
+      <li><p>One</p></li>
+    </ol>
     <h1 id="item1">[Two]</h1>
     <ol>
       <li>
diff --git a/Editor/tests/outline/heading-hierarchy03c-expected.html b/Editor/tests/outline/heading-hierarchy03c-expected.html
index daa8627..0ae7cc1 100644
--- a/Editor/tests/outline/heading-hierarchy03c-expected.html
+++ b/Editor/tests/outline/heading-hierarchy03c-expected.html
@@ -9,6 +9,8 @@
       </li>
     </ol>
     <h1 id="item1">[Four]</h1>
-    <ol><li><p>Five</p></li></ol>
+    <ol>
+      <li><p>Five</p></li>
+    </ol>
   </body>
 </html>
diff --git a/Editor/tests/outline/heading-hierarchy04a-expected.html b/Editor/tests/outline/heading-hierarchy04a-expected.html
index 6d20bab..a95e2c1 100644
--- a/Editor/tests/outline/heading-hierarchy04a-expected.html
+++ b/Editor/tests/outline/heading-hierarchy04a-expected.html
@@ -1,7 +1,9 @@
 <html>
   <head></head>
   <body>
-    <ol><li>One</li></ol>
+    <ol>
+      <li>One</li>
+    </ol>
     <h1 id="item1">[Two]</h1>
     <ol>
       <li>
diff --git a/Editor/tests/outline/heading-hierarchy04c-expected.html b/Editor/tests/outline/heading-hierarchy04c-expected.html
index 56bbcad..c320022 100644
--- a/Editor/tests/outline/heading-hierarchy04c-expected.html
+++ b/Editor/tests/outline/heading-hierarchy04c-expected.html
@@ -11,6 +11,8 @@
       </li>
     </ol>
     <h1 id="item1">[Four]</h1>
-    <ol><li>Five</li></ol>
+    <ol>
+      <li>Five</li>
+    </ol>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfFigures10-expected.html b/Editor/tests/outline/listOfFigures10-expected.html
index 3f708f6..d2216f7 100644
--- a/Editor/tests/outline/listOfFigures10-expected.html
+++ b/Editor/tests/outline/listOfFigures10-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><nav class="listoffigures"><p class="toc1">[No figures defined]</p></nav></body>
+  <body>
+    <nav class="listoffigures">
+      <p class="toc1">[No figures defined]</p>
+    </nav>
+  </body>
 </html>
diff --git a/Editor/tests/outline/listOfFigures11-expected.html b/Editor/tests/outline/listOfFigures11-expected.html
index 3f708f6..d2216f7 100644
--- a/Editor/tests/outline/listOfFigures11-expected.html
+++ b/Editor/tests/outline/listOfFigures11-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><nav class="listoffigures"><p class="toc1">[No figures defined]</p></nav></body>
+  <body>
+    <nav class="listoffigures">
+      <p class="toc1">[No figures defined]</p>
+    </nav>
+  </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables01-expected.html b/Editor/tests/outline/listOfTables01-expected.html
index d83bd48..431c04a 100644
--- a/Editor/tests/outline/listOfTables01-expected.html
+++ b/Editor/tests/outline/listOfTables01-expected.html
@@ -32,22 +32,38 @@
     <table id="item1" style="width: 100%">
       <caption>Test table A</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption>Test table B</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item3" style="width: 100%">
       <caption>Test table C</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item4" style="width: 100%">
       <caption>Test table D</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables02-expected.html b/Editor/tests/outline/listOfTables02-expected.html
index 9372ca2..56cb8d6 100644
--- a/Editor/tests/outline/listOfTables02-expected.html
+++ b/Editor/tests/outline/listOfTables02-expected.html
@@ -32,7 +32,11 @@
     <table id="item1" style="width: 100%">
       <caption>Test table A</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption>
@@ -40,17 +44,29 @@
         XYZ
       </caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item3" style="width: 100%">
       <caption>Test table C</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item4" style="width: 100%">
       <caption>Test table D</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables03-expected.html b/Editor/tests/outline/listOfTables03-expected.html
index 35b85d0..8d55a43 100644
--- a/Editor/tests/outline/listOfTables03-expected.html
+++ b/Editor/tests/outline/listOfTables03-expected.html
@@ -32,22 +32,38 @@
     <table id="item1" style="width: 100%">
       <caption>Test table A</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption>TeXYZst table B</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item3" style="width: 100%">
       <caption>Test table C</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item4" style="width: 100%">
       <caption>Test table D</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables04-expected.html b/Editor/tests/outline/listOfTables04-expected.html
index 51e410e..b6b451b 100644
--- a/Editor/tests/outline/listOfTables04-expected.html
+++ b/Editor/tests/outline/listOfTables04-expected.html
@@ -32,22 +32,38 @@
     <table id="item1" style="width: 100%">
       <caption>Test table A</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption>Teble B</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item3" style="width: 100%">
       <caption>Test table C</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item4" style="width: 100%">
       <caption>Test table D</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables05-expected.html b/Editor/tests/outline/listOfTables05-expected.html
index 28d6b4e..d630969 100644
--- a/Editor/tests/outline/listOfTables05-expected.html
+++ b/Editor/tests/outline/listOfTables05-expected.html
@@ -31,23 +31,47 @@
     </nav>
     <table id="item1" style="width: 100%">
       <caption>Test table A</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption>Test table B</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item3" style="width: 100%">
       <caption>Test table C</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item4" style="width: 100%">
       <caption>Test table D</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables06-expected.html b/Editor/tests/outline/listOfTables06-expected.html
index 5a318f2..fa069fe 100644
--- a/Editor/tests/outline/listOfTables06-expected.html
+++ b/Editor/tests/outline/listOfTables06-expected.html
@@ -11,23 +11,47 @@
     </nav>
     <table id="item1" style="width: 100%">
       <caption class="Unnumbered">Test table A</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption class="Unnumbered">Test table B</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item3" style="width: 100%">
       <caption class="Unnumbered">Test table C</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item4" style="width: 100%">
       <caption class="Unnumbered">Test table D</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables07-expected.html b/Editor/tests/outline/listOfTables07-expected.html
index 74cbb79..7e6c405 100644
--- a/Editor/tests/outline/listOfTables07-expected.html
+++ b/Editor/tests/outline/listOfTables07-expected.html
@@ -12,22 +12,38 @@
     <table id="item1" style="width: 100%">
       <caption class="Unnumbered">Test table A</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption class="Unnumbered">Test table B</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item3" style="width: 100%">
       <caption class="Unnumbered">Test table C</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item4" style="width: 100%">
       <caption class="Unnumbered">Test table D</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables08-expected.html b/Editor/tests/outline/listOfTables08-expected.html
index 74cbb79..7e6c405 100644
--- a/Editor/tests/outline/listOfTables08-expected.html
+++ b/Editor/tests/outline/listOfTables08-expected.html
@@ -12,22 +12,38 @@
     <table id="item1" style="width: 100%">
       <caption class="Unnumbered">Test table A</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption class="Unnumbered">Test table B</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item3" style="width: 100%">
       <caption class="Unnumbered">Test table C</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item4" style="width: 100%">
       <caption class="Unnumbered">Test table D</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables09-expected.html b/Editor/tests/outline/listOfTables09-expected.html
index a65575c..22f283e 100644
--- a/Editor/tests/outline/listOfTables09-expected.html
+++ b/Editor/tests/outline/listOfTables09-expected.html
@@ -22,22 +22,38 @@
     <table id="item1" style="width: 100%">
       <caption class="Unnumbered">Test table A</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption class="Unnumbered">Test table B</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item3" style="width: 100%">
       <caption>Test table C</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item4" style="width: 100%">
       <caption>Test table D</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables09a-expected.html b/Editor/tests/outline/listOfTables09a-expected.html
index d83bd48..431c04a 100644
--- a/Editor/tests/outline/listOfTables09a-expected.html
+++ b/Editor/tests/outline/listOfTables09a-expected.html
@@ -32,22 +32,38 @@
     <table id="item1" style="width: 100%">
       <caption>Test table A</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption>Test table B</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item3" style="width: 100%">
       <caption>Test table C</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item4" style="width: 100%">
       <caption>Test table D</caption>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables10-expected.html b/Editor/tests/outline/listOfTables10-expected.html
index ae022b2..a2bb877 100644
--- a/Editor/tests/outline/listOfTables10-expected.html
+++ b/Editor/tests/outline/listOfTables10-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><nav class="listoftables"><p class="toc1">[No tables defined]</p></nav></body>
+  <body>
+    <nav class="listoftables">
+      <p class="toc1">[No tables defined]</p>
+    </nav>
+  </body>
 </html>
diff --git a/Editor/tests/outline/listOfTables11-expected.html b/Editor/tests/outline/listOfTables11-expected.html
index ae022b2..a2bb877 100644
--- a/Editor/tests/outline/listOfTables11-expected.html
+++ b/Editor/tests/outline/listOfTables11-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><nav class="listoftables"><p class="toc1">[No tables defined]</p></nav></body>
+  <body>
+    <nav class="listoftables">
+      <p class="toc1">[No tables defined]</p>
+    </nav>
+  </body>
 </html>
diff --git a/Editor/tests/outline/refTitle-figure01-expected.html b/Editor/tests/outline/refTitle-figure01-expected.html
index a5bc86a..9735bee 100644
--- a/Editor/tests/outline/refTitle-figure01-expected.html
+++ b/Editor/tests/outline/refTitle-figure01-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <figure id="item1"><figcaption>First figure</figcaption></figure>
-    <figure id="item2"><figcaption>Second figure</figcaption></figure>
-    <figure id="item3"><figcaption class="Unnumbered">Third figure</figcaption></figure>
-    <figure id="item4"><figcaption class="Unnumbered">Fourth figure</figcaption></figure>
+    <figure id="item1">
+      <figcaption>First figure</figcaption>
+    </figure>
+    <figure id="item2">
+      <figcaption>Second figure</figcaption>
+    </figure>
+    <figure id="item3">
+      <figcaption class="Unnumbered">Third figure</figcaption>
+    </figure>
+    <figure id="item4">
+      <figcaption class="Unnumbered">Fourth figure</figcaption>
+    </figure>
     <p>
       First ref: Figure
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-figure03-expected.html b/Editor/tests/outline/refTitle-figure03-expected.html
index edf4979..bc2d68b 100644
--- a/Editor/tests/outline/refTitle-figure03-expected.html
+++ b/Editor/tests/outline/refTitle-figure03-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <figure id="item1"><figcaption>FiXYZrst figure</figcaption></figure>
-    <figure id="item2"><figcaption>SeXYZcond figure</figcaption></figure>
-    <figure id="item3"><figcaption class="Unnumbered">ThXYZird figure</figcaption></figure>
-    <figure id="item4"><figcaption class="Unnumbered">FoXYZurth figure</figcaption></figure>
+    <figure id="item1">
+      <figcaption>FiXYZrst figure</figcaption>
+    </figure>
+    <figure id="item2">
+      <figcaption>SeXYZcond figure</figcaption>
+    </figure>
+    <figure id="item3">
+      <figcaption class="Unnumbered">ThXYZird figure</figcaption>
+    </figure>
+    <figure id="item4">
+      <figcaption class="Unnumbered">FoXYZurth figure</figcaption>
+    </figure>
     <p>
       First ref: Figure
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-figure04-expected.html b/Editor/tests/outline/refTitle-figure04-expected.html
index 845e38b..e1a3cba 100644
--- a/Editor/tests/outline/refTitle-figure04-expected.html
+++ b/Editor/tests/outline/refTitle-figure04-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <figure id="item1"><figcaption>Fit figure</figcaption></figure>
-    <figure id="item2"><figcaption>Send figure</figcaption></figure>
-    <figure id="item3"><figcaption class="Unnumbered">Thd figure</figcaption></figure>
-    <figure id="item4"><figcaption class="Unnumbered">Foth figure</figcaption></figure>
+    <figure id="item1">
+      <figcaption>Fit figure</figcaption>
+    </figure>
+    <figure id="item2">
+      <figcaption>Send figure</figcaption>
+    </figure>
+    <figure id="item3">
+      <figcaption class="Unnumbered">Thd figure</figcaption>
+    </figure>
+    <figure id="item4">
+      <figcaption class="Unnumbered">Foth figure</figcaption>
+    </figure>
     <p>
       First ref: Figure
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-figure05-expected.html b/Editor/tests/outline/refTitle-figure05-expected.html
index 974f95a..c32c9a4 100644
--- a/Editor/tests/outline/refTitle-figure05-expected.html
+++ b/Editor/tests/outline/refTitle-figure05-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <figure id="item1"><figcaption>Figure A</figcaption></figure>
-    <figure id="item2"><figcaption>Figure B</figcaption></figure>
-    <figure id="item3"><figcaption class="Unnumbered">Figure C</figcaption></figure>
-    <figure id="item4"><figcaption class="Unnumbered">Figure D</figcaption></figure>
+    <figure id="item1">
+      <figcaption>Figure A</figcaption>
+    </figure>
+    <figure id="item2">
+      <figcaption>Figure B</figcaption>
+    </figure>
+    <figure id="item3">
+      <figcaption class="Unnumbered">Figure C</figcaption>
+    </figure>
+    <figure id="item4">
+      <figcaption class="Unnumbered">Figure D</figcaption>
+    </figure>
     <p>
       First ref: Figure
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-figure06-expected.html b/Editor/tests/outline/refTitle-figure06-expected.html
index 34c77b7..15d7200 100644
--- a/Editor/tests/outline/refTitle-figure06-expected.html
+++ b/Editor/tests/outline/refTitle-figure06-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <figure id="item1"><figcaption>First figure</figcaption></figure>
-    <figure id="item2"><figcaption class="Unnumbered">Second figure</figcaption></figure>
-    <figure id="item3"><figcaption class="Unnumbered">Third figure</figcaption></figure>
-    <figure id="item4"><figcaption class="Unnumbered">Fourth figure</figcaption></figure>
+    <figure id="item1">
+      <figcaption>First figure</figcaption>
+    </figure>
+    <figure id="item2">
+      <figcaption class="Unnumbered">Second figure</figcaption>
+    </figure>
+    <figure id="item3">
+      <figcaption class="Unnumbered">Third figure</figcaption>
+    </figure>
+    <figure id="item4">
+      <figcaption class="Unnumbered">Fourth figure</figcaption>
+    </figure>
     <p>
       First ref: Figure
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-figure07-expected.html b/Editor/tests/outline/refTitle-figure07-expected.html
index 04dc2c5..d6bc652 100644
--- a/Editor/tests/outline/refTitle-figure07-expected.html
+++ b/Editor/tests/outline/refTitle-figure07-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <figure id="item1"><figcaption>First figure</figcaption></figure>
-    <figure id="item2"><figcaption>Second figure</figcaption></figure>
-    <figure id="item3"><figcaption>Third figure</figcaption></figure>
-    <figure id="item4"><figcaption class="Unnumbered">Fourth figure</figcaption></figure>
+    <figure id="item1">
+      <figcaption>First figure</figcaption>
+    </figure>
+    <figure id="item2">
+      <figcaption>Second figure</figcaption>
+    </figure>
+    <figure id="item3">
+      <figcaption>Third figure</figcaption>
+    </figure>
+    <figure id="item4">
+      <figcaption class="Unnumbered">Fourth figure</figcaption>
+    </figure>
     <p>
       First ref: Figure
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-table01-expected.html b/Editor/tests/outline/refTitle-table01-expected.html
index de204a8..0b7d604 100644
--- a/Editor/tests/outline/refTitle-table01-expected.html
+++ b/Editor/tests/outline/refTitle-table01-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <table id="item1"><caption>First table</caption></table>
-    <table id="item2"><caption>Second table</caption></table>
-    <table id="item3"><caption class="Unnumbered">Third table</caption></table>
-    <table id="item4"><caption class="Unnumbered">Fourth table</caption></table>
+    <table id="item1">
+      <caption>First table</caption>
+    </table>
+    <table id="item2">
+      <caption>Second table</caption>
+    </table>
+    <table id="item3">
+      <caption class="Unnumbered">Third table</caption>
+    </table>
+    <table id="item4">
+      <caption class="Unnumbered">Fourth table</caption>
+    </table>
     <p>
       First ref: Table
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-table03-expected.html b/Editor/tests/outline/refTitle-table03-expected.html
index 4d4b717..dd48fea 100644
--- a/Editor/tests/outline/refTitle-table03-expected.html
+++ b/Editor/tests/outline/refTitle-table03-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <table id="item1"><caption>FiXYZrst table</caption></table>
-    <table id="item2"><caption>SeXYZcond table</caption></table>
-    <table id="item3"><caption class="Unnumbered">ThXYZird table</caption></table>
-    <table id="item4"><caption class="Unnumbered">FoXYZurth table</caption></table>
+    <table id="item1">
+      <caption>FiXYZrst table</caption>
+    </table>
+    <table id="item2">
+      <caption>SeXYZcond table</caption>
+    </table>
+    <table id="item3">
+      <caption class="Unnumbered">ThXYZird table</caption>
+    </table>
+    <table id="item4">
+      <caption class="Unnumbered">FoXYZurth table</caption>
+    </table>
     <p>
       First ref: Table
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-table04-expected.html b/Editor/tests/outline/refTitle-table04-expected.html
index fd0ae9d..9d59ed2 100644
--- a/Editor/tests/outline/refTitle-table04-expected.html
+++ b/Editor/tests/outline/refTitle-table04-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <table id="item1"><caption>Fit table</caption></table>
-    <table id="item2"><caption>Send table</caption></table>
-    <table id="item3"><caption class="Unnumbered">Thd table</caption></table>
-    <table id="item4"><caption class="Unnumbered">Foth table</caption></table>
+    <table id="item1">
+      <caption>Fit table</caption>
+    </table>
+    <table id="item2">
+      <caption>Send table</caption>
+    </table>
+    <table id="item3">
+      <caption class="Unnumbered">Thd table</caption>
+    </table>
+    <table id="item4">
+      <caption class="Unnumbered">Foth table</caption>
+    </table>
     <p>
       First ref: Table
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-table05-expected.html b/Editor/tests/outline/refTitle-table05-expected.html
index 0dd3e31..6aff79a 100644
--- a/Editor/tests/outline/refTitle-table05-expected.html
+++ b/Editor/tests/outline/refTitle-table05-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <table id="item1"><caption>Table A</caption></table>
-    <table id="item2"><caption>Table B</caption></table>
-    <table id="item3"><caption class="Unnumbered">Table C</caption></table>
-    <table id="item4"><caption class="Unnumbered">Table D</caption></table>
+    <table id="item1">
+      <caption>Table A</caption>
+    </table>
+    <table id="item2">
+      <caption>Table B</caption>
+    </table>
+    <table id="item3">
+      <caption class="Unnumbered">Table C</caption>
+    </table>
+    <table id="item4">
+      <caption class="Unnumbered">Table D</caption>
+    </table>
     <p>
       First ref: Table
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-table06-expected.html b/Editor/tests/outline/refTitle-table06-expected.html
index b67c018..08b25ff 100644
--- a/Editor/tests/outline/refTitle-table06-expected.html
+++ b/Editor/tests/outline/refTitle-table06-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <table id="item1"><caption>First table</caption></table>
-    <table id="item2"><caption class="Unnumbered">Second table</caption></table>
-    <table id="item3"><caption class="Unnumbered">Third table</caption></table>
-    <table id="item4"><caption class="Unnumbered">Fourth table</caption></table>
+    <table id="item1">
+      <caption>First table</caption>
+    </table>
+    <table id="item2">
+      <caption class="Unnumbered">Second table</caption>
+    </table>
+    <table id="item3">
+      <caption class="Unnumbered">Third table</caption>
+    </table>
+    <table id="item4">
+      <caption class="Unnumbered">Fourth table</caption>
+    </table>
     <p>
       First ref: Table
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/refTitle-table07-expected.html b/Editor/tests/outline/refTitle-table07-expected.html
index d9f00d0..5458f4e 100644
--- a/Editor/tests/outline/refTitle-table07-expected.html
+++ b/Editor/tests/outline/refTitle-table07-expected.html
@@ -9,10 +9,18 @@
   <head>
   </head>
   <body>
-    <table id="item1"><caption>First table</caption></table>
-    <table id="item2"><caption>Second table</caption></table>
-    <table id="item3"><caption>Third table</caption></table>
-    <table id="item4"><caption class="Unnumbered">Fourth table</caption></table>
+    <table id="item1">
+      <caption>First table</caption>
+    </table>
+    <table id="item2">
+      <caption>Second table</caption>
+    </table>
+    <table id="item3">
+      <caption>Third table</caption>
+    </table>
+    <table id="item4">
+      <caption class="Unnumbered">Fourth table</caption>
+    </table>
     <p>
       First ref: Table
       <a href="#item1">1</a>
diff --git a/Editor/tests/outline/reference-insert02-expected.html b/Editor/tests/outline/reference-insert02-expected.html
index 5a49ca9..d24c302 100644
--- a/Editor/tests/outline/reference-insert02-expected.html
+++ b/Editor/tests/outline/reference-insert02-expected.html
@@ -2,9 +2,15 @@
   <head>
   </head>
   <body>
-    <figure id="one"><figcaption></figcaption></figure>
-    <figure id="two"><figcaption></figcaption></figure>
-    <figure id="three"><figcaption></figcaption></figure>
+    <figure id="one">
+      <figcaption></figcaption>
+    </figure>
+    <figure id="two">
+      <figcaption></figcaption>
+    </figure>
+    <figure id="three">
+      <figcaption></figcaption>
+    </figure>
     <a href="#one">1</a>
     <a href="#two">2</a>
     <a href="#three">3</a>
diff --git a/Editor/tests/outline/reference-insert03-expected.html b/Editor/tests/outline/reference-insert03-expected.html
index 830beb2..a1db37e 100644
--- a/Editor/tests/outline/reference-insert03-expected.html
+++ b/Editor/tests/outline/reference-insert03-expected.html
@@ -2,9 +2,15 @@
   <head>
   </head>
   <body>
-    <table id="one"><caption></caption></table>
-    <table id="two"><caption></caption></table>
-    <table id="three"><caption></caption></table>
+    <table id="one">
+      <caption></caption>
+    </table>
+    <table id="two">
+      <caption></caption>
+    </table>
+    <table id="three">
+      <caption></caption>
+    </table>
     <a href="#one">1</a>
     <a href="#two">2</a>
     <a href="#three">3</a>
diff --git a/Editor/tests/outline/reference-static02-expected.html b/Editor/tests/outline/reference-static02-expected.html
index acac09d..bba4355 100644
--- a/Editor/tests/outline/reference-static02-expected.html
+++ b/Editor/tests/outline/reference-static02-expected.html
@@ -14,9 +14,15 @@
       Reference
       <a href="#three">3</a>
     </p>
-    <figure id="one"><figcaption></figcaption></figure>
-    <figure id="two"><figcaption></figcaption></figure>
-    <figure id="three"><figcaption></figcaption></figure>
+    <figure id="one">
+      <figcaption></figcaption>
+    </figure>
+    <figure id="two">
+      <figcaption></figcaption>
+    </figure>
+    <figure id="three">
+      <figcaption></figcaption>
+    </figure>
     <p>
       Reference
       <a href="#one">1</a>
diff --git a/Editor/tests/outline/reference-static03-expected.html b/Editor/tests/outline/reference-static03-expected.html
index 28ec138..b2638e6 100644
--- a/Editor/tests/outline/reference-static03-expected.html
+++ b/Editor/tests/outline/reference-static03-expected.html
@@ -14,9 +14,15 @@
       Reference
       <a href="#three">3</a>
     </p>
-    <table id="one"><caption></caption></table>
-    <table id="two"><caption></caption></table>
-    <table id="three"><caption></caption></table>
+    <table id="one">
+      <caption></caption>
+    </table>
+    <table id="two">
+      <caption></caption>
+    </table>
+    <table id="three">
+      <caption></caption>
+    </table>
     <p>
       Reference
       <a href="#one">1</a>
diff --git a/Editor/tests/outline/reference-update02-expected.html b/Editor/tests/outline/reference-update02-expected.html
index 7c88754..92d5bf3 100644
--- a/Editor/tests/outline/reference-update02-expected.html
+++ b/Editor/tests/outline/reference-update02-expected.html
@@ -14,10 +14,18 @@
       Reference
       <a href="#three">4</a>
     </p>
-    <figure id="one"><figcaption></figcaption></figure>
-    <figure id="item1"><figcaption></figcaption></figure>
-    <figure id="two"><figcaption></figcaption></figure>
-    <figure id="three"><figcaption></figcaption></figure>
+    <figure id="one">
+      <figcaption></figcaption>
+    </figure>
+    <figure id="item1">
+      <figcaption></figcaption>
+    </figure>
+    <figure id="two">
+      <figcaption></figcaption>
+    </figure>
+    <figure id="three">
+      <figcaption></figcaption>
+    </figure>
     <p>
       Reference
       <a href="#one">1</a>
diff --git a/Editor/tests/outline/reference-update03-expected.html b/Editor/tests/outline/reference-update03-expected.html
index f2826cc..ec4edae 100644
--- a/Editor/tests/outline/reference-update03-expected.html
+++ b/Editor/tests/outline/reference-update03-expected.html
@@ -14,10 +14,18 @@
       Reference
       <a href="#three">4</a>
     </p>
-    <table id="one"><caption></caption></table>
-    <table id="item1"><caption></caption></table>
-    <table id="two"><caption></caption></table>
-    <table id="three"><caption></caption></table>
+    <table id="one">
+      <caption></caption>
+    </table>
+    <table id="item1">
+      <caption></caption>
+    </table>
+    <table id="two">
+      <caption></caption>
+    </table>
+    <table id="three">
+      <caption></caption>
+    </table>
     <p>
       Reference
       <a href="#one">1</a>
diff --git a/Editor/tests/outline/reference01-expected.html b/Editor/tests/outline/reference01-expected.html
index f3d96e1..fd32c84 100644
--- a/Editor/tests/outline/reference01-expected.html
+++ b/Editor/tests/outline/reference01-expected.html
@@ -7,8 +7,12 @@
   </head>
   <body>
     <h1 id="item3">New section</h1>
-    <figure id="item2"><figcaption/></figure>
-    <table id="item1"><caption/></table>
+    <figure id="item2">
+      <figcaption/>
+    </figure>
+    <table id="item1">
+      <caption/>
+    </table>
     <p>
       Dynamically added reference:
       <a href="#hb">2.1</a>
diff --git a/Editor/tests/outline/refsById01-expected.html b/Editor/tests/outline/refsById01-expected.html
index 58a0237..6df1b7d 100644
--- a/Editor/tests/outline/refsById01-expected.html
+++ b/Editor/tests/outline/refsById01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1 id="item2">Second section</h1></body>
+  <body>
+    <h1 id="item2">Second section</h1>
+  </body>
 </html>
diff --git a/Editor/tests/outline/setNumbered-figure02-expected.html b/Editor/tests/outline/setNumbered-figure02-expected.html
index bd75cbf..3760ea8 100644
--- a/Editor/tests/outline/setNumbered-figure02-expected.html
+++ b/Editor/tests/outline/setNumbered-figure02-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><figure id="item1"><img src="../figures/nothing.png" width="25%"/></figure></body>
+  <body>
+    <figure id="item1">
+      <img src="../figures/nothing.png" width="25%"/>
+    </figure>
+  </body>
 </html>
diff --git a/Editor/tests/outline/tableOfContents10-expected.html b/Editor/tests/outline/tableOfContents10-expected.html
index 0be3e97..3d005dc 100644
--- a/Editor/tests/outline/tableOfContents10-expected.html
+++ b/Editor/tests/outline/tableOfContents10-expected.html
@@ -2,5 +2,9 @@
   <head>
     <link href="../generic.css" rel="stylesheet"/>
   </head>
-  <body><nav class="tableofcontents"><p class="toc1">[No sections defined]</p></nav></body>
+  <body>
+    <nav class="tableofcontents">
+      <p class="toc1">[No sections defined]</p>
+    </nav>
+  </body>
 </html>
diff --git a/Editor/tests/outline/tableOfContents11-expected.html b/Editor/tests/outline/tableOfContents11-expected.html
index fd80db1..5ef310b 100644
--- a/Editor/tests/outline/tableOfContents11-expected.html
+++ b/Editor/tests/outline/tableOfContents11-expected.html
@@ -4,5 +4,9 @@
     <style>
     </style>
   </head>
-  <body><nav class="tableofcontents"><p class="toc1">[No sections defined]</p></nav></body>
+  <body>
+    <nav class="tableofcontents">
+      <p class="toc1">[No sections defined]</p>
+    </nav>
+  </body>
 </html>
diff --git a/Editor/tests/outline/tocInsert01-expected.html b/Editor/tests/outline/tocInsert01-expected.html
index 6ca1634..1c42cb7 100644
--- a/Editor/tests/outline/tocInsert01-expected.html
+++ b/Editor/tests/outline/tocInsert01-expected.html
@@ -29,13 +29,25 @@
     </figure>
     <table id="item1" style="width: 100%">
       <caption>Test table A</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption>Test table B</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/tocInsert02-expected.html b/Editor/tests/outline/tocInsert02-expected.html
index 30ee06c..7a6dd77 100644
--- a/Editor/tests/outline/tocInsert02-expected.html
+++ b/Editor/tests/outline/tocInsert02-expected.html
@@ -31,13 +31,25 @@
     </figure>
     <table id="item1" style="width: 100%">
       <caption>Test table A</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption>Test table B</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/outline/tocInsert03-expected.html b/Editor/tests/outline/tocInsert03-expected.html
index c79557b..5b703f0 100644
--- a/Editor/tests/outline/tocInsert03-expected.html
+++ b/Editor/tests/outline/tocInsert03-expected.html
@@ -29,13 +29,25 @@
     </figure>
     <table id="item1" style="width: 100%">
       <caption>Test table A</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
     <table id="item2" style="width: 100%">
       <caption>Test table B</caption>
-      <colgroup><col width="100%"/></colgroup>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-body01a-expected.html b/Editor/tests/position/isValidCursorPosition-body01a-expected.html
index 0db0aa6..3c15d21 100644
--- a/Editor/tests/position/isValidCursorPosition-body01a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-body01a-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body>.</body>
+  <body>
+    .
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-body01b-expected.html b/Editor/tests/position/isValidCursorPosition-body01b-expected.html
index 0db0aa6..3c15d21 100644
--- a/Editor/tests/position/isValidCursorPosition-body01b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-body01b-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body>.</body>
+  <body>
+    .
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-body01c-expected.html b/Editor/tests/position/isValidCursorPosition-body01c-expected.html
index 0db0aa6..3c15d21 100644
--- a/Editor/tests/position/isValidCursorPosition-body01c-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-body01c-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body>.</body>
+  <body>
+    .
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-body01d-expected.html b/Editor/tests/position/isValidCursorPosition-body01d-expected.html
index 0db0aa6..3c15d21 100644
--- a/Editor/tests/position/isValidCursorPosition-body01d-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-body01d-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body>.</body>
+  <body>
+    .
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-body01e-expected.html b/Editor/tests/position/isValidCursorPosition-body01e-expected.html
index 0db0aa6..3c15d21 100644
--- a/Editor/tests/position/isValidCursorPosition-body01e-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-body01e-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body>.</body>
+  <body>
+    .
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-body01f-expected.html b/Editor/tests/position/isValidCursorPosition-body01f-expected.html
index 0db0aa6..3c15d21 100644
--- a/Editor/tests/position/isValidCursorPosition-body01f-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-body01f-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body>.</body>
+  <body>
+    .
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-body01g-expected.html b/Editor/tests/position/isValidCursorPosition-body01g-expected.html
index 0db0aa6..3c15d21 100644
--- a/Editor/tests/position/isValidCursorPosition-body01g-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-body01g-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body>.</body>
+  <body>
+    .
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote01-expected.html b/Editor/tests/position/isValidCursorPosition-endnote01-expected.html
new file mode 100644
index 0000000..cb7614e
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote01-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="endnote">.e.n.d.n.o.t.e.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote01-input.html b/Editor/tests/position/isValidCursorPosition-endnote01-input.html
new file mode 100644
index 0000000..3254c5e
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote01-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote">endnote</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote02-expected.html b/Editor/tests/position/isValidCursorPosition-endnote02-expected.html
new file mode 100644
index 0000000..220a4e2
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote02-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="endnote">.e.n.d.n.o.t.e.</span>
+      .
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote02-input.html b/Editor/tests/position/isValidCursorPosition-endnote02-input.html
new file mode 100644
index 0000000..ee67b8a
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote02-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote">endnote</span></p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote03-expected.html b/Editor/tests/position/isValidCursorPosition-endnote03-expected.html
new file mode 100644
index 0000000..56b5550
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote03-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .
+      <span class="endnote">.e.n.d.n.o.t.e.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote03-input.html b/Editor/tests/position/isValidCursorPosition-endnote03-input.html
new file mode 100644
index 0000000..f4b15ab
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote03-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p><span class="endnote">endnote</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote04-expected.html b/Editor/tests/position/isValidCursorPosition-endnote04-expected.html
new file mode 100644
index 0000000..f2e6bfa
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote04-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .
+      <span class="endnote">.e.n.d.n.o.t.e.</span>
+      .
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote04-input.html b/Editor/tests/position/isValidCursorPosition-endnote04-input.html
new file mode 100644
index 0000000..74a8606
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote04-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p><span class="endnote">endnote</span></p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote05-expected.html b/Editor/tests/position/isValidCursorPosition-endnote05-expected.html
new file mode 100644
index 0000000..735a24f
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote05-expected.html
@@ -0,0 +1,13 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="endnote">.f.i.r.s.t.</span>
+      .
+      <span class="endnote">.s.e.c.o.n.d.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote05-input.html b/Editor/tests/position/isValidCursorPosition-endnote05-input.html
new file mode 100644
index 0000000..91277c9
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote05-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote">first</span><span class="endnote">second</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote06-expected.html b/Editor/tests/position/isValidCursorPosition-endnote06-expected.html
new file mode 100644
index 0000000..4b5fd0b
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote06-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="endnote">.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote06-input.html b/Editor/tests/position/isValidCursorPosition-endnote06-input.html
new file mode 100644
index 0000000..ed8e9fd
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote06-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote"></span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote07-expected.html b/Editor/tests/position/isValidCursorPosition-endnote07-expected.html
new file mode 100644
index 0000000..abff27c
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote07-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="endnote">.</span>
+      .
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote07-input.html b/Editor/tests/position/isValidCursorPosition-endnote07-input.html
new file mode 100644
index 0000000..e10ba4b
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote07-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote"></span></p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote08-expected.html b/Editor/tests/position/isValidCursorPosition-endnote08-expected.html
new file mode 100644
index 0000000..bbccfb6
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote08-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .
+      <span class="endnote">.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote08-input.html b/Editor/tests/position/isValidCursorPosition-endnote08-input.html
new file mode 100644
index 0000000..0691bb8
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote08-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p><span class="endnote"></span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote09-expected.html b/Editor/tests/position/isValidCursorPosition-endnote09-expected.html
new file mode 100644
index 0000000..80c2f50
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote09-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .
+      <span class="endnote">.</span>
+      .
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote09-input.html b/Editor/tests/position/isValidCursorPosition-endnote09-input.html
new file mode 100644
index 0000000..6d4d4e0
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote09-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p><span class="endnote"></span></p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote10-expected.html b/Editor/tests/position/isValidCursorPosition-endnote10-expected.html
new file mode 100644
index 0000000..70cab9a
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote10-expected.html
@@ -0,0 +1,13 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="endnote">.</span>
+      .
+      <span class="endnote">.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-endnote10-input.html b/Editor/tests/position/isValidCursorPosition-endnote10-input.html
new file mode 100644
index 0000000..4f1a5c0
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-endnote10-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="endnote"></span><span class="endnote"></span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote01-expected.html b/Editor/tests/position/isValidCursorPosition-footnote01-expected.html
new file mode 100644
index 0000000..30baef0
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote01-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="footnote">.f.o.o.t.n.o.t.e.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote01-input.html b/Editor/tests/position/isValidCursorPosition-footnote01-input.html
new file mode 100644
index 0000000..19f828f
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote01-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">footnote</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote02-expected.html b/Editor/tests/position/isValidCursorPosition-footnote02-expected.html
new file mode 100644
index 0000000..6c640e4
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote02-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="footnote">.f.o.o.t.n.o.t.e.</span>
+      .
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote02-input.html b/Editor/tests/position/isValidCursorPosition-footnote02-input.html
new file mode 100644
index 0000000..33071e2
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote02-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">footnote</span></p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote03-expected.html b/Editor/tests/position/isValidCursorPosition-footnote03-expected.html
new file mode 100644
index 0000000..ffa20d6
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote03-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .
+      <span class="footnote">.f.o.o.t.n.o.t.e.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote03-input.html b/Editor/tests/position/isValidCursorPosition-footnote03-input.html
new file mode 100644
index 0000000..8f7f354
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote03-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p><span class="footnote">footnote</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote04-expected.html b/Editor/tests/position/isValidCursorPosition-footnote04-expected.html
new file mode 100644
index 0000000..df77fa9
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote04-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .
+      <span class="footnote">.f.o.o.t.n.o.t.e.</span>
+      .
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote04-input.html b/Editor/tests/position/isValidCursorPosition-footnote04-input.html
new file mode 100644
index 0000000..4f84bb3
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote04-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p><span class="footnote">footnote</span></p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote05-expected.html b/Editor/tests/position/isValidCursorPosition-footnote05-expected.html
new file mode 100644
index 0000000..3c42ff3
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote05-expected.html
@@ -0,0 +1,13 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="footnote">.f.i.r.s.t.</span>
+      .
+      <span class="footnote">.s.e.c.o.n.d.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote05-input.html b/Editor/tests/position/isValidCursorPosition-footnote05-input.html
new file mode 100644
index 0000000..6a41ff8
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote05-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">first</span><span class="footnote">second</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote06-expected.html b/Editor/tests/position/isValidCursorPosition-footnote06-expected.html
new file mode 100644
index 0000000..c7f7280
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote06-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="footnote">.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote06-input.html b/Editor/tests/position/isValidCursorPosition-footnote06-input.html
new file mode 100644
index 0000000..c73faa2
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote06-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote"></span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote07-expected.html b/Editor/tests/position/isValidCursorPosition-footnote07-expected.html
new file mode 100644
index 0000000..610bd41
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote07-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="footnote">.</span>
+      .
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote07-input.html b/Editor/tests/position/isValidCursorPosition-footnote07-input.html
new file mode 100644
index 0000000..50f5b25
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote07-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote"></span></p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote08-expected.html b/Editor/tests/position/isValidCursorPosition-footnote08-expected.html
new file mode 100644
index 0000000..a257091
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote08-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .
+      <span class="footnote">.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote08-input.html b/Editor/tests/position/isValidCursorPosition-footnote08-input.html
new file mode 100644
index 0000000..4e808bc
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote08-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p><span class="footnote"></span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote09-expected.html b/Editor/tests/position/isValidCursorPosition-footnote09-expected.html
new file mode 100644
index 0000000..cc1183f
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote09-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .
+      <span class="footnote">.</span>
+      .
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote09-input.html b/Editor/tests/position/isValidCursorPosition-footnote09-input.html
new file mode 100644
index 0000000..3790129
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote09-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p><span class="footnote"></span></p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote10-expected.html b/Editor/tests/position/isValidCursorPosition-footnote10-expected.html
new file mode 100644
index 0000000..b192062
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote10-expected.html
@@ -0,0 +1,13 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="footnote">.</span>
+      .
+      <span class="footnote">.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote10-input.html b/Editor/tests/position/isValidCursorPosition-footnote10-input.html
new file mode 100644
index 0000000..bcf3749
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote10-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote"></span><span class="footnote"></span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote11-expected.html b/Editor/tests/position/isValidCursorPosition-footnote11-expected.html
new file mode 100644
index 0000000..6c640e4
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote11-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="footnote">.f.o.o.t.n.o.t.e.</span>
+      .
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote11-input.html b/Editor/tests/position/isValidCursorPosition-footnote11-input.html
new file mode 100644
index 0000000..5421f92
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote11-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">footnote</span> </p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote12-expected.html b/Editor/tests/position/isValidCursorPosition-footnote12-expected.html
new file mode 100644
index 0000000..6c640e4
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote12-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .b.e.f.o.r.e.
+      <span class="footnote">.f.o.o.t.n.o.t.e.</span>
+      .
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote12-input.html b/Editor/tests/position/isValidCursorPosition-footnote12-input.html
new file mode 100644
index 0000000..a06bb2a
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote12-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>before<span class="footnote">footnote</span>  </p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote13-expected.html b/Editor/tests/position/isValidCursorPosition-footnote13-expected.html
new file mode 100644
index 0000000..ffa20d6
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote13-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .
+      <span class="footnote">.f.o.o.t.n.o.t.e.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote13-input.html b/Editor/tests/position/isValidCursorPosition-footnote13-input.html
new file mode 100644
index 0000000..14f51ba
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote13-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p> <span class="footnote">footnote</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote14-expected.html b/Editor/tests/position/isValidCursorPosition-footnote14-expected.html
new file mode 100644
index 0000000..ffa20d6
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote14-expected.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <p>
+      .
+      <span class="footnote">.f.o.o.t.n.o.t.e.</span>
+      .a.f.t.e.r.
+    </p>
+  </body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-footnote14-input.html b/Editor/tests/position/isValidCursorPosition-footnote14-input.html
new file mode 100644
index 0000000..4335720
--- /dev/null
+++ b/Editor/tests/position/isValidCursorPosition-footnote14-input.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="validPositions.js"></script>
+<script>
+function performTest()
+{
+    showValidPositions();
+}
+</script>
+</head>
+<body>
+  <p>  <span class="footnote">footnote</span>after</p>
+</body>
+</html>
diff --git a/Editor/tests/position/isValidCursorPosition-heading01a-expected.html b/Editor/tests/position/isValidCursorPosition-heading01a-expected.html
index cfa70ac..89d566b 100644
--- a/Editor/tests/position/isValidCursorPosition-heading01a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-heading01a-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><h1 id="item1">.O.n.e.</h1></body>
+  <body>
+    <h1 id="item1">.O.n.e.</h1>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-heading01b-expected.html b/Editor/tests/position/isValidCursorPosition-heading01b-expected.html
index cfa70ac..89d566b 100644
--- a/Editor/tests/position/isValidCursorPosition-heading01b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-heading01b-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><h1 id="item1">.O.n.e.</h1></body>
+  <body>
+    <h1 id="item1">.O.n.e.</h1>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-heading01c-expected.html b/Editor/tests/position/isValidCursorPosition-heading01c-expected.html
index cfa70ac..89d566b 100644
--- a/Editor/tests/position/isValidCursorPosition-heading01c-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-heading01c-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><h1 id="item1">.O.n.e.</h1></body>
+  <body>
+    <h1 id="item1">.O.n.e.</h1>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline05a-expected.html b/Editor/tests/position/isValidCursorPosition-inline05a-expected.html
index fc82311..9dcdd98 100644
--- a/Editor/tests/position/isValidCursorPosition-inline05a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline05a-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.o.n.e.</b></p></body>
+  <body>
+    <p><b>.o.n.e.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline05b-expected.html b/Editor/tests/position/isValidCursorPosition-inline05b-expected.html
index fc82311..9dcdd98 100644
--- a/Editor/tests/position/isValidCursorPosition-inline05b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline05b-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.o.n.e.</b></p></body>
+  <body>
+    <p><b>.o.n.e.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline05c-expected.html b/Editor/tests/position/isValidCursorPosition-inline05c-expected.html
index fc82311..9dcdd98 100644
--- a/Editor/tests/position/isValidCursorPosition-inline05c-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline05c-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.o.n.e.</b></p></body>
+  <body>
+    <p><b>.o.n.e.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline05d-expected.html b/Editor/tests/position/isValidCursorPosition-inline05d-expected.html
index fc82311..9dcdd98 100644
--- a/Editor/tests/position/isValidCursorPosition-inline05d-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline05d-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.o.n.e.</b></p></body>
+  <body>
+    <p><b>.o.n.e.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline05e-expected.html b/Editor/tests/position/isValidCursorPosition-inline05e-expected.html
index fc82311..9dcdd98 100644
--- a/Editor/tests/position/isValidCursorPosition-inline05e-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline05e-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.o.n.e.</b></p></body>
+  <body>
+    <p><b>.o.n.e.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline05f-expected.html b/Editor/tests/position/isValidCursorPosition-inline05f-expected.html
index fc82311..9dcdd98 100644
--- a/Editor/tests/position/isValidCursorPosition-inline05f-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline05f-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.o.n.e.</b></p></body>
+  <body>
+    <p><b>.o.n.e.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline05g-expected.html b/Editor/tests/position/isValidCursorPosition-inline05g-expected.html
index fc82311..9dcdd98 100644
--- a/Editor/tests/position/isValidCursorPosition-inline05g-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline05g-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.o.n.e.</b></p></body>
+  <body>
+    <p><b>.o.n.e.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06a-expected.html b/Editor/tests/position/isValidCursorPosition-inline06a-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06a-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06b-expected.html b/Editor/tests/position/isValidCursorPosition-inline06b-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06b-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06c-expected.html b/Editor/tests/position/isValidCursorPosition-inline06c-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06c-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06c-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06d-expected.html b/Editor/tests/position/isValidCursorPosition-inline06d-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06d-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06d-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06e-expected.html b/Editor/tests/position/isValidCursorPosition-inline06e-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06e-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06e-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06f-expected.html b/Editor/tests/position/isValidCursorPosition-inline06f-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06f-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06f-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06g-expected.html b/Editor/tests/position/isValidCursorPosition-inline06g-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06g-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06g-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06h-expected.html b/Editor/tests/position/isValidCursorPosition-inline06h-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06h-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06h-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06i-expected.html b/Editor/tests/position/isValidCursorPosition-inline06i-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06i-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06i-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06j-expected.html b/Editor/tests/position/isValidCursorPosition-inline06j-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06j-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06j-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline06k-expected.html b/Editor/tests/position/isValidCursorPosition-inline06k-expected.html
index 5ef0933..80dfe2f 100644
--- a/Editor/tests/position/isValidCursorPosition-inline06k-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline06k-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.o.n.e.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.o.n.e.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline07a-expected.html b/Editor/tests/position/isValidCursorPosition-inline07a-expected.html
index 93d9915..10a0e17 100644
--- a/Editor/tests/position/isValidCursorPosition-inline07a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline07a-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.</b></p></body>
+  <body>
+    <p><b>.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline07b-expected.html b/Editor/tests/position/isValidCursorPosition-inline07b-expected.html
index 93d9915..10a0e17 100644
--- a/Editor/tests/position/isValidCursorPosition-inline07b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline07b-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.</b></p></body>
+  <body>
+    <p><b>.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline07c-expected.html b/Editor/tests/position/isValidCursorPosition-inline07c-expected.html
index 93d9915..10a0e17 100644
--- a/Editor/tests/position/isValidCursorPosition-inline07c-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline07c-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.</b></p></body>
+  <body>
+    <p><b>.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline07d-expected.html b/Editor/tests/position/isValidCursorPosition-inline07d-expected.html
index 93d9915..10a0e17 100644
--- a/Editor/tests/position/isValidCursorPosition-inline07d-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline07d-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.</b></p></body>
+  <body>
+    <p><b>.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline07e-expected.html b/Editor/tests/position/isValidCursorPosition-inline07e-expected.html
index 93d9915..10a0e17 100644
--- a/Editor/tests/position/isValidCursorPosition-inline07e-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline07e-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.</b></p></body>
+  <body>
+    <p><b>.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline07f-expected.html b/Editor/tests/position/isValidCursorPosition-inline07f-expected.html
index 93d9915..10a0e17 100644
--- a/Editor/tests/position/isValidCursorPosition-inline07f-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline07f-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.</b></p></body>
+  <body>
+    <p><b>.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline07g-expected.html b/Editor/tests/position/isValidCursorPosition-inline07g-expected.html
index 93d9915..10a0e17 100644
--- a/Editor/tests/position/isValidCursorPosition-inline07g-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline07g-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b>.</b></p></body>
+  <body>
+    <p><b>.</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08a-expected.html b/Editor/tests/position/isValidCursorPosition-inline08a-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08a-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08b-expected.html b/Editor/tests/position/isValidCursorPosition-inline08b-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08b-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08c-expected.html b/Editor/tests/position/isValidCursorPosition-inline08c-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08c-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08c-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08d-expected.html b/Editor/tests/position/isValidCursorPosition-inline08d-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08d-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08d-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08e-expected.html b/Editor/tests/position/isValidCursorPosition-inline08e-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08e-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08e-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08f-expected.html b/Editor/tests/position/isValidCursorPosition-inline08f-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08f-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08f-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08g-expected.html b/Editor/tests/position/isValidCursorPosition-inline08g-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08g-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08g-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08h-expected.html b/Editor/tests/position/isValidCursorPosition-inline08h-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08h-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08h-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08i-expected.html b/Editor/tests/position/isValidCursorPosition-inline08i-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08i-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08i-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08j-expected.html b/Editor/tests/position/isValidCursorPosition-inline08j-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08j-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08j-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-inline08k-expected.html b/Editor/tests/position/isValidCursorPosition-inline08k-expected.html
index 6a6ff8e..b07b5c9 100644
--- a/Editor/tests/position/isValidCursorPosition-inline08k-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-inline08k-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p><b><i><u>.</u></i></b></p></body>
+  <body>
+    <p><b><i><u>.</u></i></b></p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-list05a-expected.html b/Editor/tests/position/isValidCursorPosition-list05a-expected.html
index 21b859b..4dc8667 100644
--- a/Editor/tests/position/isValidCursorPosition-list05a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-list05a-expected.html
@@ -1,5 +1,9 @@
 <html>
   <head>
   </head>
-  <body><ul><li>.</li></ul></body>
+  <body>
+    <ul>
+      <li>.</li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-list05b-expected.html b/Editor/tests/position/isValidCursorPosition-list05b-expected.html
index 21b859b..4dc8667 100644
--- a/Editor/tests/position/isValidCursorPosition-list05b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-list05b-expected.html
@@ -1,5 +1,9 @@
 <html>
   <head>
   </head>
-  <body><ul><li>.</li></ul></body>
+  <body>
+    <ul>
+      <li>.</li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph01a-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph01a-expected.html
index 466a9a0..8e95516 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph01a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph01a-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.o.n.e.</p></body>
+  <body>
+    <p>.o.n.e.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph01b-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph01b-expected.html
index 47d5423..f56b54e 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph01b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph01b-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.o.n.e. .t.w.o.</p></body>
+  <body>
+    <p>.o.n.e. .t.w.o.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph01c-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph01c-expected.html
index bf4c30d..ad4bb6b 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph01c-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph01c-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.o.n.e.   .t.w.o.</p></body>
+  <body>
+    <p>.o.n.e.   .t.w.o.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph01d-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph01d-expected.html
index 47d5423..f56b54e 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph01d-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph01d-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.o.n.e. .t.w.o.</p></body>
+  <body>
+    <p>.o.n.e. .t.w.o.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph01e-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph01e-expected.html
index bf4c30d..ad4bb6b 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph01e-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph01e-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.o.n.e.   .t.w.o.</p></body>
+  <body>
+    <p>.o.n.e.   .t.w.o.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph03a-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph03a-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph03a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph03a-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph03b-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph03b-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph03b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph03b-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph03c-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph03c-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph03c-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph03c-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph03d-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph03d-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph03d-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph03d-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph04a-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph04a-expected.html
index 466a9a0..8e95516 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph04a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph04a-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.o.n.e.</p></body>
+  <body>
+    <p>.o.n.e.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph04b-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph04b-expected.html
index 466a9a0..8e95516 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph04b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph04b-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.o.n.e.</p></body>
+  <body>
+    <p>.o.n.e.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph04c-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph04c-expected.html
index 466a9a0..8e95516 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph04c-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph04c-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.o.n.e.</p></body>
+  <body>
+    <p>.o.n.e.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph08a-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph08a-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph08a-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph08a-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph08b-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph08b-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph08b-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph08b-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph08c-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph08c-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph08c-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph08c-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph08d-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph08d-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph08d-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph08d-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph08e-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph08e-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph08e-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph08e-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph08f-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph08f-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph08f-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph08f-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/isValidCursorPosition-paragraph08g-expected.html b/Editor/tests/position/isValidCursorPosition-paragraph08g-expected.html
index 8e173c5..8c272e1 100644
--- a/Editor/tests/position/isValidCursorPosition-paragraph08g-expected.html
+++ b/Editor/tests/position/isValidCursorPosition-paragraph08g-expected.html
@@ -1,5 +1,7 @@
 <html>
   <head>
   </head>
-  <body><p>.</p></body>
+  <body>
+    <p>.</p>
+  </body>
 </html>
diff --git a/Editor/tests/position/validPositions.js b/Editor/tests/position/validPositions.js
index 4334774..e158d3f 100644
--- a/Editor/tests/position/validPositions.js
+++ b/Editor/tests/position/validPositions.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function oldInsertCharacter(character)
 {
diff --git a/Editor/tests/range/cloneContents-list05-expected.html b/Editor/tests/range/cloneContents-list05-expected.html
index 2a213b1..a5cb641 100644
--- a/Editor/tests/range/cloneContents-list05-expected.html
+++ b/Editor/tests/range/cloneContents-list05-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><ul><li>Two</li></ul></body>
+  <body>
+    <ul>
+      <li>Two</li>
+    </ul>
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents01-expected.html b/Editor/tests/range/cloneContents01-expected.html
index 7c6a501..32ad03f 100644
--- a/Editor/tests/range/cloneContents01-expected.html
+++ b/Editor/tests/range/cloneContents01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>Here is some text</body>
+  <body>
+    Here is some text
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents02-expected.html b/Editor/tests/range/cloneContents02-expected.html
index c74d525..c6d3e67 100644
--- a/Editor/tests/range/cloneContents02-expected.html
+++ b/Editor/tests/range/cloneContents02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>is some</body>
+  <body>
+    is some
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents03-expected.html b/Editor/tests/range/cloneContents03-expected.html
index 51f76c6..5c06a00 100644
--- a/Editor/tests/range/cloneContents03-expected.html
+++ b/Editor/tests/range/cloneContents03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>Here is</body>
+  <body>
+    Here is
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents04-expected.html b/Editor/tests/range/cloneContents04-expected.html
index edc19b6..a4aabd7 100644
--- a/Editor/tests/range/cloneContents04-expected.html
+++ b/Editor/tests/range/cloneContents04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>some text</body>
+  <body>
+    some text
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents05-expected.html b/Editor/tests/range/cloneContents05-expected.html
index 7c6a501..32ad03f 100644
--- a/Editor/tests/range/cloneContents05-expected.html
+++ b/Editor/tests/range/cloneContents05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>Here is some text</body>
+  <body>
+    Here is some text
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents06-expected.html b/Editor/tests/range/cloneContents06-expected.html
index c74d525..c6d3e67 100644
--- a/Editor/tests/range/cloneContents06-expected.html
+++ b/Editor/tests/range/cloneContents06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>is some</body>
+  <body>
+    is some
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents07-expected.html b/Editor/tests/range/cloneContents07-expected.html
index 51f76c6..5c06a00 100644
--- a/Editor/tests/range/cloneContents07-expected.html
+++ b/Editor/tests/range/cloneContents07-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>Here is</body>
+  <body>
+    Here is
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents08-expected.html b/Editor/tests/range/cloneContents08-expected.html
index edc19b6..a4aabd7 100644
--- a/Editor/tests/range/cloneContents08-expected.html
+++ b/Editor/tests/range/cloneContents08-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>some text</body>
+  <body>
+    some text
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents09-expected.html b/Editor/tests/range/cloneContents09-expected.html
index b450bf9..c359720 100644
--- a/Editor/tests/range/cloneContents09-expected.html
+++ b/Editor/tests/range/cloneContents09-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Here is some text</p></body>
+  <body>
+    <p>Here is some text</p>
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents10-expected.html b/Editor/tests/range/cloneContents10-expected.html
index e06d683..315c6b3 100644
--- a/Editor/tests/range/cloneContents10-expected.html
+++ b/Editor/tests/range/cloneContents10-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Here is</p></body>
+  <body>
+    <p>Here is</p>
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents11-expected.html b/Editor/tests/range/cloneContents11-expected.html
index 6cfb2d7..9e13ca6 100644
--- a/Editor/tests/range/cloneContents11-expected.html
+++ b/Editor/tests/range/cloneContents11-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>some text</p></body>
+  <body>
+    <p>some text</p>
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents12-expected.html b/Editor/tests/range/cloneContents12-expected.html
index 954f35b..7ba5c9b 100644
--- a/Editor/tests/range/cloneContents12-expected.html
+++ b/Editor/tests/range/cloneContents12-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><b><i><u>is some</u></i></b></body>
+  <body>
+    <b><i><u>is some</u></i></b>
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents13-expected.html b/Editor/tests/range/cloneContents13-expected.html
index 954f35b..7ba5c9b 100644
--- a/Editor/tests/range/cloneContents13-expected.html
+++ b/Editor/tests/range/cloneContents13-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><b><i><u>is some</u></i></b></body>
+  <body>
+    <b><i><u>is some</u></i></b>
+  </body>
 </html>
diff --git a/Editor/tests/range/cloneContents14-expected.html b/Editor/tests/range/cloneContents14-expected.html
index 954f35b..7ba5c9b 100644
--- a/Editor/tests/range/cloneContents14-expected.html
+++ b/Editor/tests/range/cloneContents14-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><b><i><u>is some</u></i></b></body>
+  <body>
+    <b><i><u>is some</u></i></b>
+  </body>
 </html>
diff --git a/Editor/tests/scan/ScanTests.js b/Editor/tests/scan/ScanTests.js
index e039a14..15fb875 100644
--- a/Editor/tests/scan/ScanTests.js
+++ b/Editor/tests/scan/ScanTests.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function testNext()
 {
diff --git a/Editor/tests/selection/PositionTests.js b/Editor/tests/selection/PositionTests.js
index 7367f9a..5b7810e 100644
--- a/Editor/tests/selection/PositionTests.js
+++ b/Editor/tests/selection/PositionTests.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function pad(str,length)
 {
diff --git a/Editor/tests/selection/delete03-expected.html b/Editor/tests/selection/delete03-expected.html
index 6ad2497..7bc65e9 100644
--- a/Editor/tests/selection/delete03-expected.html
+++ b/Editor/tests/selection/delete03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>one two three[]four five six</p></body>
+  <body>
+    <p>one two three[]four five six</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/delete04-expected.html b/Editor/tests/selection/delete04-expected.html
index 6ad2497..7bc65e9 100644
--- a/Editor/tests/selection/delete04-expected.html
+++ b/Editor/tests/selection/delete04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>one two three[]four five six</p></body>
+  <body>
+    <p>one two three[]four five six</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/delete05-expected.html b/Editor/tests/selection/delete05-expected.html
index 23d8405..54b89fd 100644
--- a/Editor/tests/selection/delete05-expected.html
+++ b/Editor/tests/selection/delete05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>one two [] five six</p></body>
+  <body>
+    <p>one two [] five six</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-list03-expected.html b/Editor/tests/selection/deleteContents-list03-expected.html
index 92a6973..0730d3f 100644
--- a/Editor/tests/selection/deleteContents-list03-expected.html
+++ b/Editor/tests/selection/deleteContents-list03-expected.html
@@ -6,7 +6,9 @@
       <li>Two</li>
       <li>Three</li>
     </ol>
-    <ol><li>Fo[]x</li></ol>
+    <ol>
+      <li>Fo[]x</li>
+    </ol>
     <ol>
       <li>Seven</li>
       <li>Eight</li>
diff --git a/Editor/tests/selection/deleteContents-list09-expected.html b/Editor/tests/selection/deleteContents-list09-expected.html
index cb347d2..a7364e1 100644
--- a/Editor/tests/selection/deleteContents-list09-expected.html
+++ b/Editor/tests/selection/deleteContents-list09-expected.html
@@ -6,7 +6,8 @@
       <li>Two</li>
       <li>Three</li>
     </ol>
-    <ol></ol>
+    <ol>
+    </ol>
     <ol>
       <li>Seven</li>
       <li>Eight</li>
diff --git a/Editor/tests/selection/deleteContents-list18-expected.html b/Editor/tests/selection/deleteContents-list18-expected.html
index 053e5fe..0629fea 100644
--- a/Editor/tests/selection/deleteContents-list18-expected.html
+++ b/Editor/tests/selection/deleteContents-list18-expected.html
@@ -2,6 +2,8 @@
   <head></head>
   <body>
     <p>Co[]wo</p>
-    <ol><li>Three</li></ol>
+    <ol>
+      <li>Three</li>
+    </ol>
   </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-paragraph-span02-expected.html b/Editor/tests/selection/deleteContents-paragraph-span02-expected.html
index 79b1ff2..cf54cc3 100644
--- a/Editor/tests/selection/deleteContents-paragraph-span02-expected.html
+++ b/Editor/tests/selection/deleteContents-paragraph-span02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p id="x2"><span id="y2">[]Two</span></p></body>
+  <body>
+    <p id="x2"><span id="y2">[]Two</span></p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-paragraph-span03-expected.html b/Editor/tests/selection/deleteContents-paragraph-span03-expected.html
index e704a19..f2546ae 100644
--- a/Editor/tests/selection/deleteContents-paragraph-span03-expected.html
+++ b/Editor/tests/selection/deleteContents-paragraph-span03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p id="x1"><span id="y1">One[]</span></p></body>
+  <body>
+    <p id="x1"><span id="y1">One[]</span></p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-paragraph02-expected.html b/Editor/tests/selection/deleteContents-paragraph02-expected.html
index 93aed95..1914faa 100644
--- a/Editor/tests/selection/deleteContents-paragraph02-expected.html
+++ b/Editor/tests/selection/deleteContents-paragraph02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p id="x2">[]Two</p></body>
+  <body>
+    <p id="x2">[]Two</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-paragraph03-expected.html b/Editor/tests/selection/deleteContents-paragraph03-expected.html
index 0cbf638..1985c41 100644
--- a/Editor/tests/selection/deleteContents-paragraph03-expected.html
+++ b/Editor/tests/selection/deleteContents-paragraph03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p id="x1">One[]</p></body>
+  <body>
+    <p id="x1">One[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-table06-expected.html b/Editor/tests/selection/deleteContents-table06-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/selection/deleteContents-table06-expected.html
+++ b/Editor/tests/selection/deleteContents-table06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-table07-expected.html b/Editor/tests/selection/deleteContents-table07-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/selection/deleteContents-table07-expected.html
+++ b/Editor/tests/selection/deleteContents-table07-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-table10-expected.html b/Editor/tests/selection/deleteContents-table10-expected.html
index 3031e70..a15e867 100644
--- a/Editor/tests/selection/deleteContents-table10-expected.html
+++ b/Editor/tests/selection/deleteContents-table10-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Content 2</p></body>
+  <body>
+    <p>Content 2</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-table11-expected.html b/Editor/tests/selection/deleteContents-table11-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/selection/deleteContents-table11-expected.html
+++ b/Editor/tests/selection/deleteContents-table11-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-table13-expected.html b/Editor/tests/selection/deleteContents-table13-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/selection/deleteContents-table13-expected.html
+++ b/Editor/tests/selection/deleteContents-table13-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents-table15-expected.html b/Editor/tests/selection/deleteContents-table15-expected.html
index db75e86..4ce7ad1 100644
--- a/Editor/tests/selection/deleteContents-table15-expected.html
+++ b/Editor/tests/selection/deleteContents-table15-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>C[]t 4</p></body>
+  <body>
+    <p>C[]t 4</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents01-expected.html b/Editor/tests/selection/deleteContents01-expected.html
index ad79c2e..4724015 100644
--- a/Editor/tests/selection/deleteContents01-expected.html
+++ b/Editor/tests/selection/deleteContents01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sa[]t</p></body>
+  <body>
+    <p>Sa[]t</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents02-expected.html b/Editor/tests/selection/deleteContents02-expected.html
index 91d0366..023378f 100644
--- a/Editor/tests/selection/deleteContents02-expected.html
+++ b/Editor/tests/selection/deleteContents02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>Sa[]</p></body>
+  <body>
+    <p>Sa[]</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents03-expected.html b/Editor/tests/selection/deleteContents03-expected.html
index 9c16a44..a293fd8 100644
--- a/Editor/tests/selection/deleteContents03-expected.html
+++ b/Editor/tests/selection/deleteContents03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>[]xt</p></body>
+  <body>
+    <p>[]xt</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents05-expected.html b/Editor/tests/selection/deleteContents05-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/selection/deleteContents05-expected.html
+++ b/Editor/tests/selection/deleteContents05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents09-expected.html b/Editor/tests/selection/deleteContents09-expected.html
index e3a4d99..c6b79d1 100644
--- a/Editor/tests/selection/deleteContents09-expected.html
+++ b/Editor/tests/selection/deleteContents09-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body>[]</body>
+  <body>
+    []
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents10-expected.html b/Editor/tests/selection/deleteContents10-expected.html
index 2f0ef70..72e0a69 100644
--- a/Editor/tests/selection/deleteContents10-expected.html
+++ b/Editor/tests/selection/deleteContents10-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>First []two</p></body>
+  <body>
+    <p>First []two</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents11-expected.html b/Editor/tests/selection/deleteContents11-expected.html
index f539041..7979222 100644
--- a/Editor/tests/selection/deleteContents11-expected.html
+++ b/Editor/tests/selection/deleteContents11-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p>First []two</p></div></body>
+  <body>
+    <div>
+      <p>First []two</p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents12-expected.html b/Editor/tests/selection/deleteContents12-expected.html
index f539041..7979222 100644
--- a/Editor/tests/selection/deleteContents12-expected.html
+++ b/Editor/tests/selection/deleteContents12-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p>First []two</p></div></body>
+  <body>
+    <div>
+      <p>First []two</p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents13-expected.html b/Editor/tests/selection/deleteContents13-expected.html
index 16bde1f..509b325 100644
--- a/Editor/tests/selection/deleteContents13-expected.html
+++ b/Editor/tests/selection/deleteContents13-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><h1>First []two</h1></body>
+  <body>
+    <h1>First []two</h1>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents14-expected.html b/Editor/tests/selection/deleteContents14-expected.html
index 375e4e1..330b717 100644
--- a/Editor/tests/selection/deleteContents14-expected.html
+++ b/Editor/tests/selection/deleteContents14-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><h1>First []two</h1></div></body>
+  <body>
+    <div>
+      <h1>First []two</h1>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents15-expected.html b/Editor/tests/selection/deleteContents15-expected.html
index 375e4e1..330b717 100644
--- a/Editor/tests/selection/deleteContents15-expected.html
+++ b/Editor/tests/selection/deleteContents15-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><h1>First []two</h1></div></body>
+  <body>
+    <div>
+      <h1>First []two</h1>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents16-expected.html b/Editor/tests/selection/deleteContents16-expected.html
index bade143..c13e48b 100644
--- a/Editor/tests/selection/deleteContents16-expected.html
+++ b/Editor/tests/selection/deleteContents16-expected.html
@@ -5,5 +5,7 @@
 .two { color: red }
     </style>
   </head>
-  <body><p class="one">First []two</p></body>
+  <body>
+    <p class="one">First []two</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents17-expected.html b/Editor/tests/selection/deleteContents17-expected.html
index 012f1fd..62a51de 100644
--- a/Editor/tests/selection/deleteContents17-expected.html
+++ b/Editor/tests/selection/deleteContents17-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p style="color: blue">First []two</p></body>
+  <body>
+    <p style="color: blue">First []two</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents18-expected.html b/Editor/tests/selection/deleteContents18-expected.html
index 2f0ef70..72e0a69 100644
--- a/Editor/tests/selection/deleteContents18-expected.html
+++ b/Editor/tests/selection/deleteContents18-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>First []two</p></body>
+  <body>
+    <p>First []two</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents18a-expected.html b/Editor/tests/selection/deleteContents18a-expected.html
index 2f0ef70..72e0a69 100644
--- a/Editor/tests/selection/deleteContents18a-expected.html
+++ b/Editor/tests/selection/deleteContents18a-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>First []two</p></body>
+  <body>
+    <p>First []two</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents18b-expected.html b/Editor/tests/selection/deleteContents18b-expected.html
index 2f0ef70..72e0a69 100644
--- a/Editor/tests/selection/deleteContents18b-expected.html
+++ b/Editor/tests/selection/deleteContents18b-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>First []two</p></body>
+  <body>
+    <p>First []two</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents19-expected.html b/Editor/tests/selection/deleteContents19-expected.html
index ea56e63..d516e02 100644
--- a/Editor/tests/selection/deleteContents19-expected.html
+++ b/Editor/tests/selection/deleteContents19-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>First []two</b></p></body>
+  <body>
+    <p><b>First []two</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents19a-expected.html b/Editor/tests/selection/deleteContents19a-expected.html
index ea56e63..d516e02 100644
--- a/Editor/tests/selection/deleteContents19a-expected.html
+++ b/Editor/tests/selection/deleteContents19a-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>First []two</b></p></body>
+  <body>
+    <p><b>First []two</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents19b-expected.html b/Editor/tests/selection/deleteContents19b-expected.html
index ea56e63..d516e02 100644
--- a/Editor/tests/selection/deleteContents19b-expected.html
+++ b/Editor/tests/selection/deleteContents19b-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p><b>First []two</b></p></body>
+  <body>
+    <p><b>First []two</b></p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents20-expected.html b/Editor/tests/selection/deleteContents20-expected.html
index f539041..7979222 100644
--- a/Editor/tests/selection/deleteContents20-expected.html
+++ b/Editor/tests/selection/deleteContents20-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p>First []two</p></div></body>
+  <body>
+    <div>
+      <p>First []two</p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents20a-expected.html b/Editor/tests/selection/deleteContents20a-expected.html
index f539041..7979222 100644
--- a/Editor/tests/selection/deleteContents20a-expected.html
+++ b/Editor/tests/selection/deleteContents20a-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p>First []two</p></div></body>
+  <body>
+    <div>
+      <p>First []two</p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/selection/deleteContents20b-expected.html b/Editor/tests/selection/deleteContents20b-expected.html
index f539041..7979222 100644
--- a/Editor/tests/selection/deleteContents20b-expected.html
+++ b/Editor/tests/selection/deleteContents20b-expected.html
@@ -1,4 +1,8 @@
 <html>
   <head></head>
-  <body><div><p>First []two</p></div></body>
+  <body>
+    <div>
+      <p>First []two</p>
+    </div>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor01-expected.html b/Editor/tests/selection/selectWordAtCursor01-expected.html
index f212d4c..06f792e 100644
--- a/Editor/tests/selection/selectWordAtCursor01-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor01-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>[One] two three</p></body>
+  <body>
+    <p>[One] two three</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor02-expected.html b/Editor/tests/selection/selectWordAtCursor02-expected.html
index f212d4c..06f792e 100644
--- a/Editor/tests/selection/selectWordAtCursor02-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor02-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>[One] two three</p></body>
+  <body>
+    <p>[One] two three</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor03-expected.html b/Editor/tests/selection/selectWordAtCursor03-expected.html
index f212d4c..06f792e 100644
--- a/Editor/tests/selection/selectWordAtCursor03-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor03-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>[One] two three</p></body>
+  <body>
+    <p>[One] two three</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor04-expected.html b/Editor/tests/selection/selectWordAtCursor04-expected.html
index 081a382..1e30363 100644
--- a/Editor/tests/selection/selectWordAtCursor04-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor04-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One [two] three</p></body>
+  <body>
+    <p>One [two] three</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor05-expected.html b/Editor/tests/selection/selectWordAtCursor05-expected.html
index 081a382..1e30363 100644
--- a/Editor/tests/selection/selectWordAtCursor05-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor05-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One [two] three</p></body>
+  <body>
+    <p>One [two] three</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor06-expected.html b/Editor/tests/selection/selectWordAtCursor06-expected.html
index 081a382..1e30363 100644
--- a/Editor/tests/selection/selectWordAtCursor06-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor06-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One [two] three</p></body>
+  <body>
+    <p>One [two] three</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor07-expected.html b/Editor/tests/selection/selectWordAtCursor07-expected.html
index ac4f980..c787408 100644
--- a/Editor/tests/selection/selectWordAtCursor07-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor07-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One two [three]</p></body>
+  <body>
+    <p>One two [three]</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor08-expected.html b/Editor/tests/selection/selectWordAtCursor08-expected.html
index ac4f980..c787408 100644
--- a/Editor/tests/selection/selectWordAtCursor08-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor08-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One two [three]</p></body>
+  <body>
+    <p>One two [three]</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor09-expected.html b/Editor/tests/selection/selectWordAtCursor09-expected.html
index ac4f980..c787408 100644
--- a/Editor/tests/selection/selectWordAtCursor09-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor09-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One two [three]</p></body>
+  <body>
+    <p>One two [three]</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor10-expected.html b/Editor/tests/selection/selectWordAtCursor10-expected.html
index ccec3ac..59a0505 100644
--- a/Editor/tests/selection/selectWordAtCursor10-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor10-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One [two $*]*!&% three four</p></body>
+  <body>
+    <p>One [two $*]*!&% three four</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor11-expected.html b/Editor/tests/selection/selectWordAtCursor11-expected.html
index c000dd9..06697fa 100644
--- a/Editor/tests/selection/selectWordAtCursor11-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor11-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One two $**![&% three] four</p></body>
+  <body>
+    <p>One two $**![&% three] four</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor12-expected.html b/Editor/tests/selection/selectWordAtCursor12-expected.html
index d5b0d6e..f2426fa 100644
--- a/Editor/tests/selection/selectWordAtCursor12-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor12-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One [two &%]&% three</p></body>
+  <body>
+    <p>One [two &%]&% three</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor13-expected.html b/Editor/tests/selection/selectWordAtCursor13-expected.html
index 76f9d35..3aaf4b6 100644
--- a/Editor/tests/selection/selectWordAtCursor13-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor13-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>[&%!.One] two three</p></body>
+  <body>
+    <p>[&%!.One] two three</p>
+  </body>
 </html>
diff --git a/Editor/tests/selection/selectWordAtCursor14-expected.html b/Editor/tests/selection/selectWordAtCursor14-expected.html
index cbad2fb..640492c 100644
--- a/Editor/tests/selection/selectWordAtCursor14-expected.html
+++ b/Editor/tests/selection/selectWordAtCursor14-expected.html
@@ -1,4 +1,6 @@
 <html>
   <head></head>
-  <body><p>One two [three&%!.]</p></body>
+  <body>
+    <p>One two [three&%!.]</p>
+  </body>
 </html>
diff --git a/Editor/tests/server.js b/Editor/tests/server.js
index 8946717..0e46945 100644
--- a/Editor/tests/server.js
+++ b/Editor/tests/server.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function debug(str)
 {
diff --git a/Editor/tests/tables/TableTests.js b/Editor/tests/tables/TableTests.js
index 5aab601..a8859e5 100644
--- a/Editor/tests/tables/TableTests.js
+++ b/Editor/tests/tables/TableTests.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function showSelectedTableRegion()
 {
diff --git a/Editor/tests/tables/addAdjacentColumn09-expected.html b/Editor/tests/tables/addAdjacentColumn09-expected.html
index 682c5c4..53c7d1f 100644
--- a/Editor/tests/tables/addAdjacentColumn09-expected.html
+++ b/Editor/tests/tables/addAdjacentColumn09-expected.html
@@ -28,7 +28,9 @@
           <td>Nine</td>
           <td colspan="4">Ten</td>
         </tr>
-        <tr><td colspan="5">Thirteen</td></tr>
+        <tr>
+          <td colspan="5">Thirteen</td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/addAdjacentColumn10-expected.html b/Editor/tests/tables/addAdjacentColumn10-expected.html
index c0e34ba..fa52b83 100644
--- a/Editor/tests/tables/addAdjacentColumn10-expected.html
+++ b/Editor/tests/tables/addAdjacentColumn10-expected.html
@@ -29,7 +29,9 @@
           <td>Nine</td>
           <td colspan="4">Ten</td>
         </tr>
-        <tr><td colspan="5">Thirteen</td></tr>
+        <tr>
+          <td colspan="5">Thirteen</td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/addAdjacentColumn11-expected.html b/Editor/tests/tables/addAdjacentColumn11-expected.html
index 3726a2f..b7b4bbe 100644
--- a/Editor/tests/tables/addAdjacentColumn11-expected.html
+++ b/Editor/tests/tables/addAdjacentColumn11-expected.html
@@ -30,7 +30,9 @@
           <td><p><br/></p></td>
           <td colspan="3">Ten</td>
         </tr>
-        <tr><td colspan="5">Thirteen</td></tr>
+        <tr>
+          <td colspan="5">Thirteen</td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/addAdjacentColumn19-expected.html b/Editor/tests/tables/addAdjacentColumn19-expected.html
new file mode 100644
index 0000000..e0db777
--- /dev/null
+++ b/Editor/tests/tables/addAdjacentColumn19-expected.html
@@ -0,0 +1,47 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    []
+    <table id="item1" style="width: 100%">
+      <colgroup>
+        <col width="20%"/>
+        <col width="20%"/>
+        <col width="20%"/>
+        <col width="20%"/>
+        <col width="20%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+          <td>One</td>
+          <td>Two</td>
+          <td>Three</td>
+          <td>Four</td>
+        </tr>
+        <tr>
+          <td><p><br/></p></td>
+          <td>Five</td>
+          <td>Six</td>
+          <td>Seven</td>
+          <td>Eight</td>
+        </tr>
+        <tr>
+          <td><p><br/></p></td>
+          <td>Nine</td>
+          <td>Ten</td>
+          <td>Eleven</td>
+          <td>Twelve</td>
+        </tr>
+        <tr>
+          <td><p><br/></p></td>
+          <td>Thirteen</td>
+          <td>Fourteen</td>
+          <td>Fifteen</td>
+          <td>Sixteen</td>
+        </tr>
+      </tbody>
+    </table>
+  </body>
+</html>
diff --git a/Editor/tests/tables/addAdjacentColumn19-input.html b/Editor/tests/tables/addAdjacentColumn19-input.html
new file mode 100644
index 0000000..c322356
--- /dev/null
+++ b/Editor/tests/tables/addAdjacentColumn19-input.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Outline_init();
+    PostponedActions_perform();
+
+    Tables_addAdjacentColumn();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  []<table style="width: 100%">
+    <col width="25%">
+    <col width="25%">
+    <col width="25%">
+    <col width="25%">
+    <tr>
+      <td>One</td>
+      <td>Two</td>
+      <td>Three</td>
+      <td>Four</td>
+    </tr>
+    <tr>
+      <td>Five</td>
+      <td>Six</td>
+      <td>Seven</td>
+      <td>Eight</td>
+    </tr>
+    <tr>
+      <td>Nine</td>
+      <td>Ten</td>
+      <td>Eleven</td>
+      <td>Twelve</td>
+    </tr>
+    <tr>
+      <td>Thirteen</td>
+      <td>Fourteen</td>
+      <td>Fifteen</td>
+      <td>Sixteen</td>
+    </tr>
+  </table>
+</body>
+</html>
diff --git a/Editor/tests/tables/addAdjacentColumn20-expected.html b/Editor/tests/tables/addAdjacentColumn20-expected.html
new file mode 100644
index 0000000..53a204e
--- /dev/null
+++ b/Editor/tests/tables/addAdjacentColumn20-expected.html
@@ -0,0 +1,47 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <table id="item1" style="width: 100%">
+      <colgroup>
+        <col width="20%"/>
+        <col width="20%"/>
+        <col width="20%"/>
+        <col width="20%"/>
+        <col width="20%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td>One</td>
+          <td>Two</td>
+          <td>Three</td>
+          <td>Four</td>
+          <td><p><br/></p></td>
+        </tr>
+        <tr>
+          <td>Five</td>
+          <td>Six</td>
+          <td>Seven</td>
+          <td>Eight</td>
+          <td><p><br/></p></td>
+        </tr>
+        <tr>
+          <td>Nine</td>
+          <td>Ten</td>
+          <td>Eleven</td>
+          <td>Twelve</td>
+          <td><p><br/></p></td>
+        </tr>
+        <tr>
+          <td>Thirteen</td>
+          <td>Fourteen</td>
+          <td>Fifteen</td>
+          <td>Sixteen</td>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
+    </table>
+    []
+  </body>
+</html>
diff --git a/Editor/tests/tables/addAdjacentColumn20-input.html b/Editor/tests/tables/addAdjacentColumn20-input.html
new file mode 100644
index 0000000..4e38d64
--- /dev/null
+++ b/Editor/tests/tables/addAdjacentColumn20-input.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Outline_init();
+    PostponedActions_perform();
+
+    Tables_addAdjacentColumn();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <table style="width: 100%">
+    <col width="25%">
+    <col width="25%">
+    <col width="25%">
+    <col width="25%">
+    <tr>
+      <td>One</td>
+      <td>Two</td>
+      <td>Three</td>
+      <td>Four</td>
+    </tr>
+    <tr>
+      <td>Five</td>
+      <td>Six</td>
+      <td>Seven</td>
+      <td>Eight</td>
+    </tr>
+    <tr>
+      <td>Nine</td>
+      <td>Ten</td>
+      <td>Eleven</td>
+      <td>Twelve</td>
+    </tr>
+    <tr>
+      <td>Thirteen</td>
+      <td>Fourteen</td>
+      <td>Fifteen</td>
+      <td>Sixteen</td>
+    </tr>
+  </table>[]
+</body>
+</html>
diff --git a/Editor/tests/tables/addAdjacentRow08-expected.html b/Editor/tests/tables/addAdjacentRow08-expected.html
index f40384f..8797a86 100644
--- a/Editor/tests/tables/addAdjacentRow08-expected.html
+++ b/Editor/tests/tables/addAdjacentRow08-expected.html
@@ -20,7 +20,9 @@
           <td>Nine</td>
           <td rowspan="2">Ten</td>
         </tr>
-        <tr><td>Thirteen]</td></tr>
+        <tr>
+          <td>Thirteen]</td>
+        </tr>
         <tr>
           <td><p><br/></p></td>
           <td><p><br/></p></td>
diff --git a/Editor/tests/tables/addAdjacentRow09-expected.html b/Editor/tests/tables/addAdjacentRow09-expected.html
index c886b41..6e56678 100644
--- a/Editor/tests/tables/addAdjacentRow09-expected.html
+++ b/Editor/tests/tables/addAdjacentRow09-expected.html
@@ -20,8 +20,12 @@
           <td>Nine]</td>
           <td rowspan="3">Ten</td>
         </tr>
-        <tr><td><p><br/></p></td></tr>
-        <tr><td>Thirteen</td></tr>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+        <tr>
+          <td>Thirteen</td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/addAdjacentRow10-expected.html b/Editor/tests/tables/addAdjacentRow10-expected.html
index b4d72da..eea0889 100644
--- a/Editor/tests/tables/addAdjacentRow10-expected.html
+++ b/Editor/tests/tables/addAdjacentRow10-expected.html
@@ -24,7 +24,9 @@
           <td>Nine</td>
           <td rowspan="2">Ten</td>
         </tr>
-        <tr><td>Thirteen</td></tr>
+        <tr>
+          <td>Thirteen</td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/addAdjacentRow11-expected.html b/Editor/tests/tables/addAdjacentRow11-expected.html
index f87f09e..30d4d73 100644
--- a/Editor/tests/tables/addAdjacentRow11-expected.html
+++ b/Editor/tests/tables/addAdjacentRow11-expected.html
@@ -25,7 +25,9 @@
           <td>Nine</td>
           <td rowspan="2">Ten</td>
         </tr>
-        <tr><td>Thirteen</td></tr>
+        <tr>
+          <td>Thirteen</td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/addAdjacentRow19-expected.html b/Editor/tests/tables/addAdjacentRow19-expected.html
new file mode 100644
index 0000000..c67b18f
--- /dev/null
+++ b/Editor/tests/tables/addAdjacentRow19-expected.html
@@ -0,0 +1,42 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    []
+    <table id="item1" style="width: 100%">
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+          <td><p><br/></p></td>
+          <td><p><br/></p></td>
+          <td><p><br/></p></td>
+        </tr>
+        <tr>
+          <td>One</td>
+          <td>Two</td>
+          <td>Three</td>
+          <td>Four</td>
+        </tr>
+        <tr>
+          <td>Five</td>
+          <td>Six</td>
+          <td>Seven</td>
+          <td>Eight</td>
+        </tr>
+        <tr>
+          <td>Nine</td>
+          <td>Ten</td>
+          <td>Eleven</td>
+          <td>Twelve</td>
+        </tr>
+        <tr>
+          <td>Thirteen</td>
+          <td>Fourteen</td>
+          <td>Fifteen</td>
+          <td>Sixteen</td>
+        </tr>
+      </tbody>
+    </table>
+  </body>
+</html>
diff --git a/Editor/tests/tables/addAdjacentRow19-input.html b/Editor/tests/tables/addAdjacentRow19-input.html
new file mode 100644
index 0000000..f87369a
--- /dev/null
+++ b/Editor/tests/tables/addAdjacentRow19-input.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Outline_init();
+    PostponedActions_perform();
+
+    Tables_addAdjacentRow();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  []<table style="width: 100%">
+    <tr>
+      <td>One</td>
+      <td>Two</td>
+      <td>Three</td>
+      <td>Four</td>
+    </tr>
+    <tr>
+      <td>Five</td>
+      <td>Six</td>
+      <td>Seven</td>
+      <td>Eight</td>
+    </tr>
+    <tr>
+      <td>Nine</td>
+      <td>Ten</td>
+      <td>Eleven</td>
+      <td>Twelve</td>
+    </tr>
+    <tr>
+      <td>Thirteen</td>
+      <td>Fourteen</td>
+      <td>Fifteen</td>
+      <td>Sixteen</td>
+    </tr>
+  </table>
+</body>
+</html>
diff --git a/Editor/tests/tables/addAdjacentRow20-expected.html b/Editor/tests/tables/addAdjacentRow20-expected.html
new file mode 100644
index 0000000..2fb326a
--- /dev/null
+++ b/Editor/tests/tables/addAdjacentRow20-expected.html
@@ -0,0 +1,42 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <table id="item1" style="width: 100%">
+      <tbody>
+        <tr>
+          <td>One</td>
+          <td>Two</td>
+          <td>Three</td>
+          <td>Four</td>
+        </tr>
+        <tr>
+          <td>Five</td>
+          <td>Six</td>
+          <td>Seven</td>
+          <td>Eight</td>
+        </tr>
+        <tr>
+          <td>Nine</td>
+          <td>Ten</td>
+          <td>Eleven</td>
+          <td>Twelve</td>
+        </tr>
+        <tr>
+          <td>Thirteen</td>
+          <td>Fourteen</td>
+          <td>Fifteen</td>
+          <td>Sixteen</td>
+        </tr>
+        <tr>
+          <td><p><br/></p></td>
+          <td><p><br/></p></td>
+          <td><p><br/></p></td>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
+    </table>
+    []
+  </body>
+</html>
diff --git a/Editor/tests/tables/addAdjacentRow20-input.html b/Editor/tests/tables/addAdjacentRow20-input.html
new file mode 100644
index 0000000..83921d1
--- /dev/null
+++ b/Editor/tests/tables/addAdjacentRow20-input.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="../generic.css" rel="stylesheet"/>
+<script>
+function performTest()
+{
+    Outline_init();
+    PostponedActions_perform();
+
+    Tables_addAdjacentRow();
+    showSelection();
+}
+</script>
+</head>
+<body>
+  <table style="width: 100%">
+    <tr>
+      <td>One</td>
+      <td>Two</td>
+      <td>Three</td>
+      <td>Four</td>
+    </tr>
+    <tr>
+      <td>Five</td>
+      <td>Six</td>
+      <td>Seven</td>
+      <td>Eight</td>
+    </tr>
+    <tr>
+      <td>Nine</td>
+      <td>Ten</td>
+      <td>Eleven</td>
+      <td>Twelve</td>
+    </tr>
+    <tr>
+      <td>Thirteen</td>
+      <td>Fourteen</td>
+      <td>Fifteen</td>
+      <td>Sixteen</td>
+    </tr>
+  </table>[]
+</body>
+</html>
diff --git a/Editor/tests/tables/deleteOneColumn07-expected.html b/Editor/tests/tables/deleteOneColumn07-expected.html
deleted file mode 100644
index e828269..0000000
--- a/Editor/tests/tables/deleteOneColumn07-expected.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<html>
-  <head>
-    <link href="../generic.css" rel="stylesheet"/>
-  </head>
-  <body>
-    <table style="width: 100%">
-      <colgroup><col width="100%"/></colgroup>
-      <tbody>
-        <tr><td><p>0,0</p></td></tr>
-        <tr><td><p>[1,0</p></td></tr>
-        <tr><td><p>2,0]</p></td></tr>
-        <tr><td><p>3,0</p></td></tr>
-      </tbody>
-    </table>
-  </body>
-</html>
diff --git a/Editor/tests/tables/fixTable02-expected.html b/Editor/tests/tables/fixTable02-expected.html
index 22ba80b..a14d9fb 100644
--- a/Editor/tests/tables/fixTable02-expected.html
+++ b/Editor/tests/tables/fixTable02-expected.html
@@ -4,7 +4,9 @@
   <body>
     <table border="1" width="100%">
       <tbody>
-        <tr><td colspan="2">A</td></tr>
+        <tr>
+          <td colspan="2">A</td>
+        </tr>
         <tr>
           <td>B</td>
           <td>C</td>
diff --git a/Editor/tests/tables/fixTable03-expected.html b/Editor/tests/tables/fixTable03-expected.html
index 3742346..1fda674 100644
--- a/Editor/tests/tables/fixTable03-expected.html
+++ b/Editor/tests/tables/fixTable03-expected.html
@@ -4,7 +4,9 @@
   <body>
     <table border="1" width="100%">
       <tbody>
-        <tr><td colspan="3">A</td></tr>
+        <tr>
+          <td colspan="3">A</td>
+        </tr>
         <tr>
           <td>B</td>
           <td>C</td>
diff --git a/Editor/tests/tables/fixTable05-expected.html b/Editor/tests/tables/fixTable05-expected.html
index 0b41c14..df344b3 100644
--- a/Editor/tests/tables/fixTable05-expected.html
+++ b/Editor/tests/tables/fixTable05-expected.html
@@ -8,7 +8,9 @@
           <td>A</td>
           <td>B</td>
         </tr>
-        <tr><td colspan="2">C</td></tr>
+        <tr>
+          <td colspan="2">C</td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/fixTable06-expected.html b/Editor/tests/tables/fixTable06-expected.html
index 82030aa..826350f 100644
--- a/Editor/tests/tables/fixTable06-expected.html
+++ b/Editor/tests/tables/fixTable06-expected.html
@@ -9,7 +9,9 @@
           <td>B</td>
           <td><p><br/></p></td>
         </tr>
-        <tr><td colspan="3">C</td></tr>
+        <tr>
+          <td colspan="3">C</td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/fixTable10-expected.html b/Editor/tests/tables/fixTable10-expected.html
index 321886f..982d54a 100644
--- a/Editor/tests/tables/fixTable10-expected.html
+++ b/Editor/tests/tables/fixTable10-expected.html
@@ -9,7 +9,9 @@
           <td rowspan="2">B</td>
           <td>C</td>
         </tr>
-        <tr><td><p><br/></p></td></tr>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/fixTable12-expected.html b/Editor/tests/tables/fixTable12-expected.html
index e9b8e66..d093ef1 100644
--- a/Editor/tests/tables/fixTable12-expected.html
+++ b/Editor/tests/tables/fixTable12-expected.html
@@ -8,7 +8,8 @@
           <td rowspan="3">A</td>
           <td rowspan="3">B</td>
         </tr>
-        <tr></tr>
+        <tr>
+        </tr>
         <tr/>
       </tbody>
     </table>
diff --git a/Editor/tests/tables/fixTable13-expected.html b/Editor/tests/tables/fixTable13-expected.html
index 20546c1..fe8ddfd 100644
--- a/Editor/tests/tables/fixTable13-expected.html
+++ b/Editor/tests/tables/fixTable13-expected.html
@@ -9,7 +9,9 @@
           <td rowspan="2">B</td>
           <td>C</td>
         </tr>
-        <tr><td><p><br/></p></td></tr>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/fixTable14-expected.html b/Editor/tests/tables/fixTable14-expected.html
index 9fe286d..24775ec 100644
--- a/Editor/tests/tables/fixTable14-expected.html
+++ b/Editor/tests/tables/fixTable14-expected.html
@@ -9,8 +9,12 @@
           <td rowspan="3">B</td>
           <td>C</td>
         </tr>
-        <tr><td><p><br/></p></td></tr>
-        <tr><td><p><br/></p></td></tr>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/fixTable15-expected.html b/Editor/tests/tables/fixTable15-expected.html
index 08b5351..0fa26c0 100644
--- a/Editor/tests/tables/fixTable15-expected.html
+++ b/Editor/tests/tables/fixTable15-expected.html
@@ -9,8 +9,12 @@
           <td rowspan="3">B</td>
           <td>C</td>
         </tr>
-        <tr><td>D</td></tr>
-        <tr><td><p><br/></p></td></tr>
+        <tr>
+          <td>D</td>
+        </tr>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/insertTable06-expected.html b/Editor/tests/tables/insertTable06-expected.html
index f2729c7..0e03215 100644
--- a/Editor/tests/tables/insertTable06-expected.html
+++ b/Editor/tests/tables/insertTable06-expected.html
@@ -7,7 +7,11 @@
     <table id="item1" style="width: 100%">
       <caption/>
       <col width="100%"/>
-      <tbody><tr><td><p><br/></p></td></tr></tbody>
+      <tbody>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+      </tbody>
     </table>
   </body>
 </html>
diff --git a/Editor/tests/tables/insertTable07-expected.html b/Editor/tests/tables/insertTable07-expected.html
index 54161c9..72baaa4 100644
--- a/Editor/tests/tables/insertTable07-expected.html
+++ b/Editor/tests/tables/insertTable07-expected.html
@@ -8,8 +8,12 @@
       <caption/>
       <col width="100%"/>
       <tbody>
-        <tr><td><p><br/></p></td></tr>
-        <tr><td><p><br/></p></td></tr>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
+        <tr>
+          <td><p><br/></p></td>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/deleteOneColumn01inside-expected.html b/Editor/tests/tables/removeAdjacentColumn01inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn01inside-expected.html
rename to Editor/tests/tables/removeAdjacentColumn01inside-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn01inside-input.html b/Editor/tests/tables/removeAdjacentColumn01inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn01inside-input.html
rename to Editor/tests/tables/removeAdjacentColumn01inside-input.html
index f58d1c1..a381aaf 100644
--- a/Editor/tests/tables/deleteOneColumn01inside-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn01inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn01right-expected.html b/Editor/tests/tables/removeAdjacentColumn01right-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn01right-expected.html
rename to Editor/tests/tables/removeAdjacentColumn01right-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn01right-input.html b/Editor/tests/tables/removeAdjacentColumn01right-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn01right-input.html
rename to Editor/tests/tables/removeAdjacentColumn01right-input.html
index 7d3bbd8..3b31e14 100644
--- a/Editor/tests/tables/deleteOneColumn01right-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn01right-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn02inside-expected.html b/Editor/tests/tables/removeAdjacentColumn02inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn02inside-expected.html
rename to Editor/tests/tables/removeAdjacentColumn02inside-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn02inside-input.html b/Editor/tests/tables/removeAdjacentColumn02inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn02inside-input.html
rename to Editor/tests/tables/removeAdjacentColumn02inside-input.html
index fb076dc..c528ba5 100644
--- a/Editor/tests/tables/deleteOneColumn02inside-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn02inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn02left-expected.html b/Editor/tests/tables/removeAdjacentColumn02left-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn02left-expected.html
rename to Editor/tests/tables/removeAdjacentColumn02left-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn02left-input.html b/Editor/tests/tables/removeAdjacentColumn02left-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn02left-input.html
rename to Editor/tests/tables/removeAdjacentColumn02left-input.html
index 42add40..8c0c646 100644
--- a/Editor/tests/tables/deleteOneColumn02left-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn02left-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn02right-expected.html b/Editor/tests/tables/removeAdjacentColumn02right-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn02right-expected.html
rename to Editor/tests/tables/removeAdjacentColumn02right-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn02right-input.html b/Editor/tests/tables/removeAdjacentColumn02right-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn02right-input.html
rename to Editor/tests/tables/removeAdjacentColumn02right-input.html
index 031e055..2ca8351 100644
--- a/Editor/tests/tables/deleteOneColumn02right-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn02right-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn03inside-expected.html b/Editor/tests/tables/removeAdjacentColumn03inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn03inside-expected.html
rename to Editor/tests/tables/removeAdjacentColumn03inside-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn03inside-input.html b/Editor/tests/tables/removeAdjacentColumn03inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn03inside-input.html
rename to Editor/tests/tables/removeAdjacentColumn03inside-input.html
index 63ada30..1504e64 100644
--- a/Editor/tests/tables/deleteOneColumn03inside-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn03inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn03left-expected.html b/Editor/tests/tables/removeAdjacentColumn03left-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn03left-expected.html
rename to Editor/tests/tables/removeAdjacentColumn03left-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn03left-input.html b/Editor/tests/tables/removeAdjacentColumn03left-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn03left-input.html
rename to Editor/tests/tables/removeAdjacentColumn03left-input.html
index d97286e..989affe 100644
--- a/Editor/tests/tables/deleteOneColumn03left-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn03left-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn04inside-expected.html b/Editor/tests/tables/removeAdjacentColumn04inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn04inside-expected.html
rename to Editor/tests/tables/removeAdjacentColumn04inside-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn04inside-input.html b/Editor/tests/tables/removeAdjacentColumn04inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn04inside-input.html
rename to Editor/tests/tables/removeAdjacentColumn04inside-input.html
index ffb79da..67424e4 100644
--- a/Editor/tests/tables/deleteOneColumn04inside-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn04inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn04right-expected.html b/Editor/tests/tables/removeAdjacentColumn04right-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn04right-expected.html
rename to Editor/tests/tables/removeAdjacentColumn04right-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn04right-input.html b/Editor/tests/tables/removeAdjacentColumn04right-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn04right-input.html
rename to Editor/tests/tables/removeAdjacentColumn04right-input.html
index cf1d950..5359736 100644
--- a/Editor/tests/tables/deleteOneColumn04right-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn04right-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn05inside-expected.html b/Editor/tests/tables/removeAdjacentColumn05inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn05inside-expected.html
rename to Editor/tests/tables/removeAdjacentColumn05inside-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn05inside-input.html b/Editor/tests/tables/removeAdjacentColumn05inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn05inside-input.html
rename to Editor/tests/tables/removeAdjacentColumn05inside-input.html
index 5a9cb92..830ea14 100644
--- a/Editor/tests/tables/deleteOneColumn05inside-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn05inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn05left-expected.html b/Editor/tests/tables/removeAdjacentColumn05left-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn05left-expected.html
rename to Editor/tests/tables/removeAdjacentColumn05left-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn05left-input.html b/Editor/tests/tables/removeAdjacentColumn05left-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn05left-input.html
rename to Editor/tests/tables/removeAdjacentColumn05left-input.html
index ed54558..23b2240 100644
--- a/Editor/tests/tables/deleteOneColumn05left-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn05left-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn05right-expected.html b/Editor/tests/tables/removeAdjacentColumn05right-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn05right-expected.html
rename to Editor/tests/tables/removeAdjacentColumn05right-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn05right-input.html b/Editor/tests/tables/removeAdjacentColumn05right-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn05right-input.html
rename to Editor/tests/tables/removeAdjacentColumn05right-input.html
index 0e561ed..b54f0f9 100644
--- a/Editor/tests/tables/deleteOneColumn05right-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn05right-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn06inside-expected.html b/Editor/tests/tables/removeAdjacentColumn06inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn06inside-expected.html
rename to Editor/tests/tables/removeAdjacentColumn06inside-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn06inside-input.html b/Editor/tests/tables/removeAdjacentColumn06inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn06inside-input.html
rename to Editor/tests/tables/removeAdjacentColumn06inside-input.html
index 54e25fb..9068a9d 100644
--- a/Editor/tests/tables/deleteOneColumn06inside-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn06inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneColumn06left-expected.html b/Editor/tests/tables/removeAdjacentColumn06left-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneColumn06left-expected.html
rename to Editor/tests/tables/removeAdjacentColumn06left-expected.html
diff --git a/Editor/tests/tables/deleteOneColumn06left-input.html b/Editor/tests/tables/removeAdjacentColumn06left-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneColumn06left-input.html
rename to Editor/tests/tables/removeAdjacentColumn06left-input.html
index 776422c..689b078 100644
--- a/Editor/tests/tables/deleteOneColumn06left-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn06left-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/removeAdjacentColumn07-expected.html b/Editor/tests/tables/removeAdjacentColumn07-expected.html
new file mode 100644
index 0000000..059c3c3
--- /dev/null
+++ b/Editor/tests/tables/removeAdjacentColumn07-expected.html
@@ -0,0 +1,26 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <table style="width: 100%">
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p>0,0</p></td>
+        </tr>
+        <tr>
+          <td><p>[1,0</p></td>
+        </tr>
+        <tr>
+          <td><p>2,0]</p></td>
+        </tr>
+        <tr>
+          <td><p>3,0</p></td>
+        </tr>
+      </tbody>
+    </table>
+  </body>
+</html>
diff --git a/Editor/tests/tables/deleteOneColumn07-input.html b/Editor/tests/tables/removeAdjacentColumn07-input.html
similarity index 92%
rename from Editor/tests/tables/deleteOneColumn07-input.html
rename to Editor/tests/tables/removeAdjacentColumn07-input.html
index 7413665..dadd8a6 100644
--- a/Editor/tests/tables/deleteOneColumn07-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn07-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/removeAdjacentColumn08-expected.html b/Editor/tests/tables/removeAdjacentColumn08-expected.html
new file mode 100644
index 0000000..2810099
--- /dev/null
+++ b/Editor/tests/tables/removeAdjacentColumn08-expected.html
@@ -0,0 +1,42 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    []
+    <table style="width: 100%">
+      <colgroup>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p>0,1</p></td>
+          <td><p>0,2</p></td>
+          <td><p>0,3</p></td>
+          <td><p>0,4</p></td>
+        </tr>
+        <tr>
+          <td><p>1,1</p></td>
+          <td><p>1,2</p></td>
+          <td><p>1,3</p></td>
+          <td><p>1,4</p></td>
+        </tr>
+        <tr>
+          <td><p>2,1</p></td>
+          <td><p>2,2</p></td>
+          <td><p>2,3</p></td>
+          <td><p>2,4</p></td>
+        </tr>
+        <tr>
+          <td><p>3,1</p></td>
+          <td><p>3,2</p></td>
+          <td><p>3,3</p></td>
+          <td><p>3,4</p></td>
+        </tr>
+      </tbody>
+    </table>
+  </body>
+</html>
diff --git a/Editor/tests/tables/deleteOneColumn04inside-input.html b/Editor/tests/tables/removeAdjacentColumn08-input.html
similarity index 87%
copy from Editor/tests/tables/deleteOneColumn04inside-input.html
copy to Editor/tests/tables/removeAdjacentColumn08-input.html
index ffb79da..df864bf 100644
--- a/Editor/tests/tables/deleteOneColumn04inside-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn08-input.html
@@ -5,13 +5,13 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
 </head>
 <body>
-  <table style="width: 100%">
+  []<table style="width: 100%">
     <col width="20%">
     <col width="20%">
     <col width="20%">
@@ -25,7 +25,7 @@
       <td><p>0,4</p></td>
     </tr>
     <tr>
-      <td><p>[1,0</p></td>
+      <td><p>1,0</p></td>
       <td><p>1,1</p></td>
       <td><p>1,2</p></td>
       <td><p>1,3</p></td>
@@ -33,7 +33,7 @@
     </tr>
     <tr>
       <td><p>2,0</p></td>
-      <td><p>2,1]</p></td>
+      <td><p>2,1</p></td>
       <td><p>2,2</p></td>
       <td><p>2,3</p></td>
       <td><p>2,4</p></td>
diff --git a/Editor/tests/tables/removeAdjacentColumn09-expected.html b/Editor/tests/tables/removeAdjacentColumn09-expected.html
new file mode 100644
index 0000000..087bce4
--- /dev/null
+++ b/Editor/tests/tables/removeAdjacentColumn09-expected.html
@@ -0,0 +1,42 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <table style="width: 100%">
+      <colgroup>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p>0,0</p></td>
+          <td><p>0,1</p></td>
+          <td><p>0,2</p></td>
+          <td><p>0,3</p></td>
+        </tr>
+        <tr>
+          <td><p>1,0</p></td>
+          <td><p>1,1</p></td>
+          <td><p>1,2</p></td>
+          <td><p>1,3</p></td>
+        </tr>
+        <tr>
+          <td><p>2,0</p></td>
+          <td><p>2,1</p></td>
+          <td><p>2,2</p></td>
+          <td><p>2,3</p></td>
+        </tr>
+        <tr>
+          <td><p>3,0</p></td>
+          <td><p>3,1</p></td>
+          <td><p>3,2</p></td>
+          <td><p>3,3</p></td>
+        </tr>
+      </tbody>
+    </table>
+    []
+  </body>
+</html>
diff --git a/Editor/tests/tables/deleteOneColumn04inside-input.html b/Editor/tests/tables/removeAdjacentColumn09-input.html
similarity index 89%
copy from Editor/tests/tables/deleteOneColumn04inside-input.html
copy to Editor/tests/tables/removeAdjacentColumn09-input.html
index ffb79da..f877401 100644
--- a/Editor/tests/tables/deleteOneColumn04inside-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn09-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
@@ -25,7 +25,7 @@
       <td><p>0,4</p></td>
     </tr>
     <tr>
-      <td><p>[1,0</p></td>
+      <td><p>1,0</p></td>
       <td><p>1,1</p></td>
       <td><p>1,2</p></td>
       <td><p>1,3</p></td>
@@ -33,7 +33,7 @@
     </tr>
     <tr>
       <td><p>2,0</p></td>
-      <td><p>2,1]</p></td>
+      <td><p>2,1</p></td>
       <td><p>2,2</p></td>
       <td><p>2,3</p></td>
       <td><p>2,4</p></td>
@@ -45,6 +45,6 @@
       <td><p>3,3</p></td>
       <td><p>3,4</p></td>
     </tr>
-  </table>
+  </table>[]
 </body>
 </html>
diff --git a/Editor/tests/tables/removeAdjacentColumn10-expected.html b/Editor/tests/tables/removeAdjacentColumn10-expected.html
new file mode 100644
index 0000000..fa8d9dd
--- /dev/null
+++ b/Editor/tests/tables/removeAdjacentColumn10-expected.html
@@ -0,0 +1,27 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    []
+    <table style="width: 100%">
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p>0,0</p></td>
+        </tr>
+        <tr>
+          <td><p>1,0</p></td>
+        </tr>
+        <tr>
+          <td><p>2,0</p></td>
+        </tr>
+        <tr>
+          <td><p>3,0</p></td>
+        </tr>
+      </tbody>
+    </table>
+  </body>
+</html>
diff --git a/Editor/tests/tables/deleteOneColumn07-input.html b/Editor/tests/tables/removeAdjacentColumn10-input.html
similarity index 73%
copy from Editor/tests/tables/deleteOneColumn07-input.html
copy to Editor/tests/tables/removeAdjacentColumn10-input.html
index 7413665..011384e 100644
--- a/Editor/tests/tables/deleteOneColumn07-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn10-input.html
@@ -5,22 +5,22 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+//    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
 </head>
 <body>
-  <table style="width: 100%">
+  []<table style="width: 100%">
     <col width="100%">
     <tr>
       <td><p>0,0</p></td>
     </tr>
     <tr>
-      <td><p>[1,0</p></td>
+      <td><p>1,0</p></td>
     </tr>
     <tr>
-      <td><p>2,0]</p></td>
+      <td><p>2,0</p></td>
     </tr>
     <tr>
       <td><p>3,0</p></td>
diff --git a/Editor/tests/tables/removeAdjacentColumn11-expected.html b/Editor/tests/tables/removeAdjacentColumn11-expected.html
new file mode 100644
index 0000000..e694a4e
--- /dev/null
+++ b/Editor/tests/tables/removeAdjacentColumn11-expected.html
@@ -0,0 +1,27 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <table style="width: 100%">
+      <colgroup>
+        <col width="100%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p>0,0</p></td>
+        </tr>
+        <tr>
+          <td><p>1,0</p></td>
+        </tr>
+        <tr>
+          <td><p>2,0</p></td>
+        </tr>
+        <tr>
+          <td><p>3,0</p></td>
+        </tr>
+      </tbody>
+    </table>
+    []
+  </body>
+</html>
diff --git a/Editor/tests/tables/deleteOneColumn07-input.html b/Editor/tests/tables/removeAdjacentColumn11-input.html
similarity index 77%
copy from Editor/tests/tables/deleteOneColumn07-input.html
copy to Editor/tests/tables/removeAdjacentColumn11-input.html
index 7413665..3061811 100644
--- a/Editor/tests/tables/deleteOneColumn07-input.html
+++ b/Editor/tests/tables/removeAdjacentColumn11-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneColumn();
+    Tables_removeAdjacentColumn();
     showSelection();
 }
 </script>
@@ -17,14 +17,14 @@
       <td><p>0,0</p></td>
     </tr>
     <tr>
-      <td><p>[1,0</p></td>
+      <td><p>1,0</p></td>
     </tr>
     <tr>
-      <td><p>2,0]</p></td>
+      <td><p>2,0</p></td>
     </tr>
     <tr>
       <td><p>3,0</p></td>
     </tr>
-  </table>
+  </table>[]
 </body>
 </html>
diff --git a/Editor/tests/tables/deleteOneRow01below-expected.html b/Editor/tests/tables/removeAdjacentRow01below-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow01below-expected.html
rename to Editor/tests/tables/removeAdjacentRow01below-expected.html
diff --git a/Editor/tests/tables/deleteOneRow01below-input.html b/Editor/tests/tables/removeAdjacentRow01below-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow01below-input.html
rename to Editor/tests/tables/removeAdjacentRow01below-input.html
index 47fa205..a2813dc 100644
--- a/Editor/tests/tables/deleteOneRow01below-input.html
+++ b/Editor/tests/tables/removeAdjacentRow01below-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow01inside-expected.html b/Editor/tests/tables/removeAdjacentRow01inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow01inside-expected.html
rename to Editor/tests/tables/removeAdjacentRow01inside-expected.html
diff --git a/Editor/tests/tables/deleteOneRow01inside-input.html b/Editor/tests/tables/removeAdjacentRow01inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow01inside-input.html
rename to Editor/tests/tables/removeAdjacentRow01inside-input.html
index c5c8663..b57af94 100644
--- a/Editor/tests/tables/deleteOneRow01inside-input.html
+++ b/Editor/tests/tables/removeAdjacentRow01inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow02above-expected.html b/Editor/tests/tables/removeAdjacentRow02above-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow02above-expected.html
rename to Editor/tests/tables/removeAdjacentRow02above-expected.html
diff --git a/Editor/tests/tables/deleteOneRow02above-input.html b/Editor/tests/tables/removeAdjacentRow02above-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow02above-input.html
rename to Editor/tests/tables/removeAdjacentRow02above-input.html
index d9ea4d6..0fb49bb 100644
--- a/Editor/tests/tables/deleteOneRow02above-input.html
+++ b/Editor/tests/tables/removeAdjacentRow02above-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow02below-expected.html b/Editor/tests/tables/removeAdjacentRow02below-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow02below-expected.html
rename to Editor/tests/tables/removeAdjacentRow02below-expected.html
diff --git a/Editor/tests/tables/deleteOneRow02below-input.html b/Editor/tests/tables/removeAdjacentRow02below-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow02below-input.html
rename to Editor/tests/tables/removeAdjacentRow02below-input.html
index f44b583..1db0c1d 100644
--- a/Editor/tests/tables/deleteOneRow02below-input.html
+++ b/Editor/tests/tables/removeAdjacentRow02below-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow02inside-expected.html b/Editor/tests/tables/removeAdjacentRow02inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow02inside-expected.html
rename to Editor/tests/tables/removeAdjacentRow02inside-expected.html
diff --git a/Editor/tests/tables/deleteOneRow02inside-input.html b/Editor/tests/tables/removeAdjacentRow02inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow02inside-input.html
rename to Editor/tests/tables/removeAdjacentRow02inside-input.html
index d88d8b8..40cce6d 100644
--- a/Editor/tests/tables/deleteOneRow02inside-input.html
+++ b/Editor/tests/tables/removeAdjacentRow02inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow03above-expected.html b/Editor/tests/tables/removeAdjacentRow03above-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow03above-expected.html
rename to Editor/tests/tables/removeAdjacentRow03above-expected.html
diff --git a/Editor/tests/tables/deleteOneRow03above-input.html b/Editor/tests/tables/removeAdjacentRow03above-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow03above-input.html
rename to Editor/tests/tables/removeAdjacentRow03above-input.html
index ad40dad..12f68ce 100644
--- a/Editor/tests/tables/deleteOneRow03above-input.html
+++ b/Editor/tests/tables/removeAdjacentRow03above-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow03inside-expected.html b/Editor/tests/tables/removeAdjacentRow03inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow03inside-expected.html
rename to Editor/tests/tables/removeAdjacentRow03inside-expected.html
diff --git a/Editor/tests/tables/deleteOneRow03inside-input.html b/Editor/tests/tables/removeAdjacentRow03inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow03inside-input.html
rename to Editor/tests/tables/removeAdjacentRow03inside-input.html
index 0407d3c..dc8d190 100644
--- a/Editor/tests/tables/deleteOneRow03inside-input.html
+++ b/Editor/tests/tables/removeAdjacentRow03inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow04below-expected.html b/Editor/tests/tables/removeAdjacentRow04below-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow04below-expected.html
rename to Editor/tests/tables/removeAdjacentRow04below-expected.html
diff --git a/Editor/tests/tables/deleteOneRow04below-input.html b/Editor/tests/tables/removeAdjacentRow04below-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow04below-input.html
rename to Editor/tests/tables/removeAdjacentRow04below-input.html
index 5a3da46..042f77a 100644
--- a/Editor/tests/tables/deleteOneRow04below-input.html
+++ b/Editor/tests/tables/removeAdjacentRow04below-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow04inside-expected.html b/Editor/tests/tables/removeAdjacentRow04inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow04inside-expected.html
rename to Editor/tests/tables/removeAdjacentRow04inside-expected.html
diff --git a/Editor/tests/tables/deleteOneRow04inside-input.html b/Editor/tests/tables/removeAdjacentRow04inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow04inside-input.html
rename to Editor/tests/tables/removeAdjacentRow04inside-input.html
index e8b6a05..2635da4 100644
--- a/Editor/tests/tables/deleteOneRow04inside-input.html
+++ b/Editor/tests/tables/removeAdjacentRow04inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow05above-expected.html b/Editor/tests/tables/removeAdjacentRow05above-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow05above-expected.html
rename to Editor/tests/tables/removeAdjacentRow05above-expected.html
diff --git a/Editor/tests/tables/deleteOneRow05above-input.html b/Editor/tests/tables/removeAdjacentRow05above-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow05above-input.html
rename to Editor/tests/tables/removeAdjacentRow05above-input.html
index 1001311..d17d0fe 100644
--- a/Editor/tests/tables/deleteOneRow05above-input.html
+++ b/Editor/tests/tables/removeAdjacentRow05above-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow05below-expected.html b/Editor/tests/tables/removeAdjacentRow05below-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow05below-expected.html
rename to Editor/tests/tables/removeAdjacentRow05below-expected.html
diff --git a/Editor/tests/tables/deleteOneRow05below-input.html b/Editor/tests/tables/removeAdjacentRow05below-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow05below-input.html
rename to Editor/tests/tables/removeAdjacentRow05below-input.html
index a152f4f..0576bb3 100644
--- a/Editor/tests/tables/deleteOneRow05below-input.html
+++ b/Editor/tests/tables/removeAdjacentRow05below-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow05inside-expected.html b/Editor/tests/tables/removeAdjacentRow05inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow05inside-expected.html
rename to Editor/tests/tables/removeAdjacentRow05inside-expected.html
diff --git a/Editor/tests/tables/deleteOneRow05inside-input.html b/Editor/tests/tables/removeAdjacentRow05inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow05inside-input.html
rename to Editor/tests/tables/removeAdjacentRow05inside-input.html
index ff66abd..0cc0dee 100644
--- a/Editor/tests/tables/deleteOneRow05inside-input.html
+++ b/Editor/tests/tables/removeAdjacentRow05inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow06above-expected.html b/Editor/tests/tables/removeAdjacentRow06above-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow06above-expected.html
rename to Editor/tests/tables/removeAdjacentRow06above-expected.html
diff --git a/Editor/tests/tables/deleteOneRow06above-input.html b/Editor/tests/tables/removeAdjacentRow06above-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow06above-input.html
rename to Editor/tests/tables/removeAdjacentRow06above-input.html
index ab594f3..e684b7b 100644
--- a/Editor/tests/tables/deleteOneRow06above-input.html
+++ b/Editor/tests/tables/removeAdjacentRow06above-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow06inside-expected.html b/Editor/tests/tables/removeAdjacentRow06inside-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow06inside-expected.html
rename to Editor/tests/tables/removeAdjacentRow06inside-expected.html
diff --git a/Editor/tests/tables/deleteOneRow06inside-input.html b/Editor/tests/tables/removeAdjacentRow06inside-input.html
similarity index 96%
rename from Editor/tests/tables/deleteOneRow06inside-input.html
rename to Editor/tests/tables/removeAdjacentRow06inside-input.html
index 7f7a31a..08ac7bc 100644
--- a/Editor/tests/tables/deleteOneRow06inside-input.html
+++ b/Editor/tests/tables/removeAdjacentRow06inside-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/deleteOneRow07-expected.html b/Editor/tests/tables/removeAdjacentRow07-expected.html
similarity index 100%
rename from Editor/tests/tables/deleteOneRow07-expected.html
rename to Editor/tests/tables/removeAdjacentRow07-expected.html
diff --git a/Editor/tests/tables/deleteOneRow07-input.html b/Editor/tests/tables/removeAdjacentRow07-input.html
similarity index 92%
rename from Editor/tests/tables/deleteOneRow07-input.html
rename to Editor/tests/tables/removeAdjacentRow07-input.html
index 20fd50c..6d81993 100644
--- a/Editor/tests/tables/deleteOneRow07-input.html
+++ b/Editor/tests/tables/removeAdjacentRow07-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
diff --git a/Editor/tests/tables/removeAdjacentRow08-expected.html b/Editor/tests/tables/removeAdjacentRow08-expected.html
new file mode 100644
index 0000000..54d8c53
--- /dev/null
+++ b/Editor/tests/tables/removeAdjacentRow08-expected.html
@@ -0,0 +1,42 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    []
+    <table style="width: 100%">
+      <colgroup>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p>1,0</p></td>
+          <td><p>1,1</p></td>
+          <td><p>1,2</p></td>
+          <td><p>1,3</p></td>
+        </tr>
+        <tr>
+          <td><p>2,0</p></td>
+          <td><p>2,1</p></td>
+          <td><p>2,2</p></td>
+          <td><p>2,3</p></td>
+        </tr>
+        <tr>
+          <td><p>3,0</p></td>
+          <td><p>3,1</p></td>
+          <td><p>3,2</p></td>
+          <td><p>3,3</p></td>
+        </tr>
+        <tr>
+          <td><p>4,0</p></td>
+          <td><p>4,1</p></td>
+          <td><p>4,2</p></td>
+          <td><p>4,3</p></td>
+        </tr>
+      </tbody>
+    </table>
+  </body>
+</html>
diff --git a/Editor/tests/tables/deleteOneRow02inside-input.html b/Editor/tests/tables/removeAdjacentRow08-input.html
similarity index 87%
copy from Editor/tests/tables/deleteOneRow02inside-input.html
copy to Editor/tests/tables/removeAdjacentRow08-input.html
index d88d8b8..1d35691 100644
--- a/Editor/tests/tables/deleteOneRow02inside-input.html
+++ b/Editor/tests/tables/removeAdjacentRow08-input.html
@@ -5,13 +5,13 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
 </head>
 <body>
-  <table style="width: 100%">
+  []<table style="width: 100%">
     <col width="25%">
     <col width="25%">
     <col width="25%">
@@ -30,8 +30,8 @@
     </tr>
     <tr>
       <td><p>2,0</p></td>
-      <td><p>[2,1</p></td>
-      <td><p>2,2]</p></td>
+      <td><p>2,1</p></td>
+      <td><p>2,2</p></td>
       <td><p>2,3</p></td>
     </tr>
     <tr>
diff --git a/Editor/tests/tables/removeAdjacentRow09-expected.html b/Editor/tests/tables/removeAdjacentRow09-expected.html
new file mode 100644
index 0000000..087bce4
--- /dev/null
+++ b/Editor/tests/tables/removeAdjacentRow09-expected.html
@@ -0,0 +1,42 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <table style="width: 100%">
+      <colgroup>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p>0,0</p></td>
+          <td><p>0,1</p></td>
+          <td><p>0,2</p></td>
+          <td><p>0,3</p></td>
+        </tr>
+        <tr>
+          <td><p>1,0</p></td>
+          <td><p>1,1</p></td>
+          <td><p>1,2</p></td>
+          <td><p>1,3</p></td>
+        </tr>
+        <tr>
+          <td><p>2,0</p></td>
+          <td><p>2,1</p></td>
+          <td><p>2,2</p></td>
+          <td><p>2,3</p></td>
+        </tr>
+        <tr>
+          <td><p>3,0</p></td>
+          <td><p>3,1</p></td>
+          <td><p>3,2</p></td>
+          <td><p>3,3</p></td>
+        </tr>
+      </tbody>
+    </table>
+    []
+  </body>
+</html>
diff --git a/Editor/tests/tables/deleteOneRow02inside-input.html b/Editor/tests/tables/removeAdjacentRow09-input.html
similarity index 89%
copy from Editor/tests/tables/deleteOneRow02inside-input.html
copy to Editor/tests/tables/removeAdjacentRow09-input.html
index d88d8b8..69f7752 100644
--- a/Editor/tests/tables/deleteOneRow02inside-input.html
+++ b/Editor/tests/tables/removeAdjacentRow09-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
@@ -30,8 +30,8 @@
     </tr>
     <tr>
       <td><p>2,0</p></td>
-      <td><p>[2,1</p></td>
-      <td><p>2,2]</p></td>
+      <td><p>2,1</p></td>
+      <td><p>2,2</p></td>
       <td><p>2,3</p></td>
     </tr>
     <tr>
@@ -46,6 +46,6 @@
       <td><p>4,2</p></td>
       <td><p>4,3</p></td>
     </tr>
-  </table>
+  </table>[]
 </body>
 </html>
diff --git a/Editor/tests/tables/removeAdjacentRow10-expected.html b/Editor/tests/tables/removeAdjacentRow10-expected.html
new file mode 100644
index 0000000..ac57961
--- /dev/null
+++ b/Editor/tests/tables/removeAdjacentRow10-expected.html
@@ -0,0 +1,24 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    []
+    <table style="width: 100%">
+      <colgroup>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p>0,0</p></td>
+          <td><p>0,1</p></td>
+          <td><p>0,2</p></td>
+          <td><p>0,3</p></td>
+        </tr>
+      </tbody>
+    </table>
+  </body>
+</html>
diff --git a/Editor/tests/tables/deleteOneRow07-input.html b/Editor/tests/tables/removeAdjacentRow10-input.html
similarity index 80%
copy from Editor/tests/tables/deleteOneRow07-input.html
copy to Editor/tests/tables/removeAdjacentRow10-input.html
index 20fd50c..1a91121 100644
--- a/Editor/tests/tables/deleteOneRow07-input.html
+++ b/Editor/tests/tables/removeAdjacentRow10-input.html
@@ -5,12 +5,13 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
 </head>
 <body>
+  []
   <table style="width: 100%">
     <col width="25%">
     <col width="25%">
@@ -18,8 +19,8 @@
     <col width="25%">
     <tr>
       <td><p>0,0</p></td>
-      <td><p>[0,1</p></td>
-      <td><p>0,2]</p></td>
+      <td><p>0,1</p></td>
+      <td><p>0,2</p></td>
       <td><p>0,3</p></td>
     </tr>
   </table>
diff --git a/Editor/tests/tables/removeAdjacentRow11-expected.html b/Editor/tests/tables/removeAdjacentRow11-expected.html
new file mode 100644
index 0000000..cb021f8
--- /dev/null
+++ b/Editor/tests/tables/removeAdjacentRow11-expected.html
@@ -0,0 +1,24 @@
+<html>
+  <head>
+    <link href="../generic.css" rel="stylesheet"/>
+  </head>
+  <body>
+    <table style="width: 100%">
+      <colgroup>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+        <col width="25%"/>
+      </colgroup>
+      <tbody>
+        <tr>
+          <td><p>0,0</p></td>
+          <td><p>0,1</p></td>
+          <td><p>0,2</p></td>
+          <td><p>0,3</p></td>
+        </tr>
+      </tbody>
+    </table>
+    []
+  </body>
+</html>
diff --git a/Editor/tests/tables/deleteOneRow07-input.html b/Editor/tests/tables/removeAdjacentRow11-input.html
similarity index 80%
copy from Editor/tests/tables/deleteOneRow07-input.html
copy to Editor/tests/tables/removeAdjacentRow11-input.html
index 20fd50c..75e4f26 100644
--- a/Editor/tests/tables/deleteOneRow07-input.html
+++ b/Editor/tests/tables/removeAdjacentRow11-input.html
@@ -5,7 +5,7 @@
 <script>
 function performTest()
 {
-    Tables_deleteOneRow();
+    Tables_removeAdjacentRow();
     showSelection();
 }
 </script>
@@ -18,10 +18,11 @@
     <col width="25%">
     <tr>
       <td><p>0,0</p></td>
-      <td><p>[0,1</p></td>
-      <td><p>0,2]</p></td>
+      <td><p>0,1</p></td>
+      <td><p>0,2</p></td>
       <td><p>0,3</p></td>
     </tr>
   </table>
+  []
 </body>
 </html>
diff --git a/Editor/tests/tables/split09a-expected.html b/Editor/tests/tables/split09a-expected.html
index 58c16a2..4526939 100644
--- a/Editor/tests/tables/split09a-expected.html
+++ b/Editor/tests/tables/split09a-expected.html
@@ -23,8 +23,11 @@
           <td><p><br/></p></td>
           <td><p><br/></p></td>
         </tr>
-        <tr><td colspan="4" rowspan="2">Nine</td></tr>
-        <tr></tr>
+        <tr>
+          <td colspan="4" rowspan="2">Nine</td>
+        </tr>
+        <tr>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/split09b-expected.html b/Editor/tests/tables/split09b-expected.html
index a41780d..594415d 100644
--- a/Editor/tests/tables/split09b-expected.html
+++ b/Editor/tests/tables/split09b-expected.html
@@ -11,8 +11,11 @@
         <col width="25%"/>
       </colgroup>
       <tbody>
-        <tr><td colspan="4" rowspan="2">One</td></tr>
-        <tr></tr>
+        <tr>
+          <td colspan="4" rowspan="2">One</td>
+        </tr>
+        <tr>
+        </tr>
         <tr>
           <td>[Nine]</td>
           <td><p><br/></p></td>
diff --git a/Editor/tests/tables/split11a-expected.html b/Editor/tests/tables/split11a-expected.html
index d25eb28..fe05858 100644
--- a/Editor/tests/tables/split11a-expected.html
+++ b/Editor/tests/tables/split11a-expected.html
@@ -27,7 +27,8 @@
           <td colspan="2" rowspan="2">Nine</td>
           <td colspan="2" rowspan="2">Eleven</td>
         </tr>
-        <tr></tr>
+        <tr>
+        </tr>
       </tbody>
     </table>
   </body>
diff --git a/Editor/tests/tables/split11c-expected.html b/Editor/tests/tables/split11c-expected.html
index 5516442..5318bcf 100644
--- a/Editor/tests/tables/split11c-expected.html
+++ b/Editor/tests/tables/split11c-expected.html
@@ -15,7 +15,8 @@
           <td colspan="2" rowspan="2">One</td>
           <td colspan="2" rowspan="2">Three</td>
         </tr>
-        <tr></tr>
+        <tr>
+        </tr>
         <tr>
           <td colspan="2" rowspan="2">Nine</td>
           <td>[Eleven]</td>
diff --git a/Editor/tests/test-structure.html b/Editor/tests/test-structure.html
index fef592c..9188155 100644
--- a/Editor/tests/test-structure.html
+++ b/Editor/tests/test-structure.html
@@ -1,5 +1,22 @@
 <!DOCTYPE html>
-<!-- Copyright (c) 2011-2013 UX Productivity Pty Ltd. All rights reserved. -->
+<!--
+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.
+-->
 <html>
 <head>
 <script type="text/javascript" src="../Outline_js"></script>
diff --git a/Editor/tests/testharness.js b/Editor/tests/testharness.js
index 775ad79..3f7f8e6 100644
--- a/Editor/tests/testharness.js
+++ b/Editor/tests/testharness.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var topArea;
 var leftArea;
diff --git a/Editor/tests/testlib.js b/Editor/tests/testlib.js
index 0e20e7a..b2eb47f 100644
--- a/Editor/tests/testlib.js
+++ b/Editor/tests/testlib.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function testHarnessSetup()
 {
diff --git a/Editor/tests/text/TextTests.js b/Editor/tests/text/TextTests.js
index 4fcd608..22a8305 100644
--- a/Editor/tests/text/TextTests.js
+++ b/Editor/tests/text/TextTests.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function showRuns()
 {
diff --git a/Editor/tests/undo/UndoTests.js b/Editor/tests/undo/UndoTests.js
index 4118caf..6a6203c 100644
--- a/Editor/tests/undo/UndoTests.js
+++ b/Editor/tests/undo/UndoTests.js
@@ -1,16 +1,19 @@
-// Copyright 2011-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 function testUndo(versions,node)
 {
diff --git a/Editor/tests/undo/insertFigure01-expected.html b/Editor/tests/undo/insertFigure01-expected.html
index 47f9a59..8c8b293 100644
--- a/Editor/tests/undo/insertFigure01-expected.html
+++ b/Editor/tests/undo/insertFigure01-expected.html
@@ -3,9 +3,12 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
-    <body><figure id="item1"/></body>
+    <body>
+      <figure id="item1"/>
+    </body>
     ==================== Version 2 ====================
     <body>
       <figure id="item1"/>
diff --git a/Editor/tests/undo/insertFigure02-expected.html b/Editor/tests/undo/insertFigure02-expected.html
index 9937fc5..1e4087f 100644
--- a/Editor/tests/undo/insertFigure02-expected.html
+++ b/Editor/tests/undo/insertFigure02-expected.html
@@ -3,7 +3,8 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
     <body>
       <figure id="item1">
diff --git a/Editor/tests/undo/insertFigure03-expected.html b/Editor/tests/undo/insertFigure03-expected.html
index 7e3c2cd..cc2b051 100644
--- a/Editor/tests/undo/insertFigure03-expected.html
+++ b/Editor/tests/undo/insertFigure03-expected.html
@@ -3,7 +3,8 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
     <body>
       <figure id="item1">
diff --git a/Editor/tests/undo/insertFigure04-expected.html b/Editor/tests/undo/insertFigure04-expected.html
index d59dd34..ed5b543 100644
--- a/Editor/tests/undo/insertFigure04-expected.html
+++ b/Editor/tests/undo/insertFigure04-expected.html
@@ -3,26 +3,49 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
-    <body><figure id="item1"><img src="first.png" style="width: 100%"/></figure></body>
+    <body>
+      <figure id="item1">
+        <img src="first.png" style="width: 100%"/>
+      </figure>
+    </body>
     ==================== Version 2 ====================
     <body>
-      <figure id="item1"><img src="first.png" style="width: 100%"/></figure>
-      <figure id="item2"><img src="second.png" style="width: 90%"/></figure>
+      <figure id="item1">
+        <img src="first.png" style="width: 100%"/>
+      </figure>
+      <figure id="item2">
+        <img src="second.png" style="width: 90%"/>
+      </figure>
     </body>
     ==================== Version 3 ====================
     <body>
-      <figure id="item1"><img src="first.png" style="width: 100%"/></figure>
-      <figure id="item3"><img src="third.png" style="width: 80%"/></figure>
-      <figure id="item2"><img src="second.png" style="width: 90%"/></figure>
+      <figure id="item1">
+        <img src="first.png" style="width: 100%"/>
+      </figure>
+      <figure id="item3">
+        <img src="third.png" style="width: 80%"/>
+      </figure>
+      <figure id="item2">
+        <img src="second.png" style="width: 90%"/>
+      </figure>
     </body>
     ==================== Version 4 ====================
     <body>
-      <figure id="item1"><img src="first.png" style="width: 100%"/></figure>
-      <figure id="item3"><img src="third.png" style="width: 80%"/></figure>
-      <figure id="item2"><img src="second.png" style="width: 90%"/></figure>
-      <figure id="item4"><img src="fourth.png" style="width: 70%"/></figure>
+      <figure id="item1">
+        <img src="first.png" style="width: 100%"/>
+      </figure>
+      <figure id="item3">
+        <img src="third.png" style="width: 80%"/>
+      </figure>
+      <figure id="item2">
+        <img src="second.png" style="width: 90%"/>
+      </figure>
+      <figure id="item4">
+        <img src="fourth.png" style="width: 70%"/>
+      </figure>
     </body>
     ===================================================
     First undo to version 3: OK
diff --git a/Editor/tests/undo/insertFigure05-expected.html b/Editor/tests/undo/insertFigure05-expected.html
index 6dc9c26..08c19fd 100644
--- a/Editor/tests/undo/insertFigure05-expected.html
+++ b/Editor/tests/undo/insertFigure05-expected.html
@@ -3,7 +3,8 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
     <body>
       <figure id="item1">
diff --git a/Editor/tests/undo/insertHeading01-expected.html b/Editor/tests/undo/insertHeading01-expected.html
index 8711722..210888c 100644
--- a/Editor/tests/undo/insertHeading01-expected.html
+++ b/Editor/tests/undo/insertHeading01-expected.html
@@ -3,9 +3,12 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
-    <body><h1 class="Unnumbered" id="item1">First heading</h1></body>
+    <body>
+      <h1 class="Unnumbered" id="item1">First heading</h1>
+    </body>
     ==================== Version 2 ====================
     <body>
       <h1 class="Unnumbered" id="item1">First heading</h1>
diff --git a/Editor/tests/undo/insertHeading02-expected.html b/Editor/tests/undo/insertHeading02-expected.html
index fafe8ca..4c0151c 100644
--- a/Editor/tests/undo/insertHeading02-expected.html
+++ b/Editor/tests/undo/insertHeading02-expected.html
@@ -3,9 +3,12 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
-    <body><h1 id="item1">First heading</h1></body>
+    <body>
+      <h1 id="item1">First heading</h1>
+    </body>
     ==================== Version 2 ====================
     <body>
       <h1 id="item1">First heading</h1>
diff --git a/Editor/tests/undo/insertTable01-expected.html b/Editor/tests/undo/insertTable01-expected.html
index 63b6def..94a6b6b 100644
--- a/Editor/tests/undo/insertTable01-expected.html
+++ b/Editor/tests/undo/insertTable01-expected.html
@@ -3,9 +3,12 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
-    <body><table id="item1" style="width: 100%"/></body>
+    <body>
+      <table id="item1" style="width: 100%"/>
+    </body>
     ==================== Version 2 ====================
     <body>
       <table id="item1" style="width: 100%"/>
diff --git a/Editor/tests/undo/insertTable02-expected.html b/Editor/tests/undo/insertTable02-expected.html
index 758e463..dc9a81c 100644
--- a/Editor/tests/undo/insertTable02-expected.html
+++ b/Editor/tests/undo/insertTable02-expected.html
@@ -3,13 +3,18 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
     <body>
       <table id="item1" style="width: 100%">
         <caption class="Unnumbered">First table</caption>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
     </body>
     ==================== Version 2 ====================
@@ -17,7 +22,11 @@
       <table id="item1" style="width: 100%">
         <caption class="Unnumbered">First table</caption>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item2" style="width: 90%">
         <caption class="Unnumbered">Second table</caption>
@@ -36,7 +45,11 @@
       <table id="item1" style="width: 100%">
         <caption class="Unnumbered">First table</caption>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item3" style="width: 80%">
         <caption class="Unnumbered">Third table</caption>
@@ -68,7 +81,11 @@
       <table id="item1" style="width: 100%">
         <caption class="Unnumbered">First table</caption>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item3" style="width: 80%">
         <caption class="Unnumbered">Third table</caption>
diff --git a/Editor/tests/undo/insertTable03-expected.html b/Editor/tests/undo/insertTable03-expected.html
index 0380c35..0b41870 100644
--- a/Editor/tests/undo/insertTable03-expected.html
+++ b/Editor/tests/undo/insertTable03-expected.html
@@ -3,13 +3,18 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
     <body>
       <table id="item1" style="width: 100%">
         <caption>First table</caption>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
     </body>
     ==================== Version 2 ====================
@@ -17,7 +22,11 @@
       <table id="item1" style="width: 100%">
         <caption>First table</caption>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item2" style="width: 90%">
         <caption>Second table</caption>
@@ -36,7 +45,11 @@
       <table id="item1" style="width: 100%">
         <caption>First table</caption>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item3" style="width: 80%">
         <caption>Third table</caption>
@@ -68,7 +81,11 @@
       <table id="item1" style="width: 100%">
         <caption>First table</caption>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item3" style="width: 80%">
         <caption>Third table</caption>
diff --git a/Editor/tests/undo/insertTable04-expected.html b/Editor/tests/undo/insertTable04-expected.html
index d65ebbf..a759e40 100644
--- a/Editor/tests/undo/insertTable04-expected.html
+++ b/Editor/tests/undo/insertTable04-expected.html
@@ -3,19 +3,28 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
     <body>
       <table id="item1" style="width: 100%">
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
     </body>
     ==================== Version 2 ====================
     <body>
       <table id="item1" style="width: 100%">
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item2" style="width: 90%">
         <col width="50%"/>
@@ -32,7 +41,11 @@
     <body>
       <table id="item1" style="width: 100%">
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item3" style="width: 80%">
         <col width="33%"/>
@@ -61,7 +74,11 @@
     <body>
       <table id="item1" style="width: 100%">
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item3" style="width: 80%">
         <col width="33%"/>
diff --git a/Editor/tests/undo/insertTable05-expected.html b/Editor/tests/undo/insertTable05-expected.html
index a8876e4..2fe5cee 100644
--- a/Editor/tests/undo/insertTable05-expected.html
+++ b/Editor/tests/undo/insertTable05-expected.html
@@ -3,13 +3,18 @@
   </head>
   <body>
     ==================== Version 0 ====================
-    <body></body>
+    <body>
+    </body>
     ==================== Version 1 ====================
     <body>
       <table id="item1" style="width: 100%">
         <caption/>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
     </body>
     ==================== Version 2 ====================
@@ -17,7 +22,11 @@
       <table id="item1" style="width: 100%">
         <caption/>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item2" style="width: 90%">
         <caption/>
@@ -36,7 +45,11 @@
       <table id="item1" style="width: 100%">
         <caption/>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item3" style="width: 80%">
         <caption/>
@@ -68,7 +81,11 @@
       <table id="item1" style="width: 100%">
         <caption/>
         <col width="100%"/>
-        <tbody><tr><td><p><br/></p></td></tr></tbody>
+        <tbody>
+          <tr>
+            <td><p><br/></p></td>
+          </tr>
+        </tbody>
       </table>
       <table id="item3" style="width: 80%">
         <caption/>
diff --git a/NOTICE.txt b/NOTICE.txt
new file mode 100644
index 0000000..89fa063
--- /dev/null
+++ b/NOTICE.txt
@@ -0,0 +1,7 @@
+Apache Corinthia (incubating)
+Copyright 2014-2015 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This product includes software copyright 2011-2015 UX Productivity Pty Ltd.
diff --git a/consumers/corinthia/.gitignore b/consumers/corinthia/.gitignore
new file mode 100644
index 0000000..8e695ec
--- /dev/null
+++ b/consumers/corinthia/.gitignore
@@ -0,0 +1 @@
+doc
diff --git a/consumers/corinthia/Doxyfile b/consumers/corinthia/Doxyfile
new file mode 100644
index 0000000..7f34338
--- /dev/null
+++ b/consumers/corinthia/Doxyfile
@@ -0,0 +1,2331 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "My Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH      =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/consumers/corinthia/res/sample.html b/consumers/corinthia/res/sample.html
new file mode 100644
index 0000000..ef8be70
--- /dev/null
+++ b/consumers/corinthia/res/sample.html
@@ -0,0 +1,395 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+  <meta name="generator" content="UX Write 2.1.1 (build ad61a0a); iOS 8.2">
+  <meta charset="utf-8">
+  <style>
+body {
+    font-family: Palatino;
+    counter-reset: h1 h2 h3 h4 h5 h6 figure table;
+    margin: 10%;
+    text-align: justify;
+  }
+
+  caption {
+    caption-side: bottom;
+    counter-increment: table;
+  }
+
+  caption.Unnumbered {
+    counter-increment: table 0;
+  }
+
+  caption.Unnumbered::before {
+    content: "";
+  }
+
+  caption::before {
+    content: "Table " counter(table) ": ";
+  }
+
+  h1 {
+    counter-increment: h1;
+    counter-reset: h2 h3 h4 h5 h6;
+  }
+
+  h1::before {
+    content: counter(h1) " ";
+  }
+
+  h2 {
+    counter-increment: h2;
+    counter-reset: h3 h4 h5 h6;
+  }
+
+  h2::before {
+    content: counter(h1) "." counter(h2) " ";
+  }
+
+  h3 {
+    counter-increment: h3;
+    counter-reset: h4 h5 h6;
+  }
+
+  h3::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) " ";
+  }
+
+  h4 {
+    counter-increment: h4;
+    counter-reset: h5 h6;
+  }
+
+  h4::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) " ";
+  }
+
+  h5 {
+    counter-increment: h5;
+    counter-reset: h6;
+  }
+
+  h5::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) " ";
+  }
+
+  h6 {
+    counter-increment: h6;
+  }
+
+  h6::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) " ";
+  }
+
+  nav.tableofcontents::before {
+    content: "Contents";
+    display: block;
+    font-size: 2em;
+    font-weight: bold;
+    margin-bottom: .67em;
+    margin-top: .67em;
+  }
+
+  p.toc1 {
+    margin-bottom: 6pt;
+    margin-left: 0pt;
+    margin-top: 12pt;
+  }
+
+  p.toc2 {
+    margin-bottom: 6pt;
+    margin-left: 24pt;
+    margin-top: 6pt;
+  }
+
+  p.toc3 {
+    margin-bottom: 6pt;
+    margin-left: 48pt;
+    margin-top: 6pt;
+  }
+
+  table {
+    border-collapse: collapse;
+    margin-left: auto;
+    margin-right: auto;
+  }
+
+  td > :first-child, th > :first-child {
+    margin-top: 0;
+  }
+
+  td > :last-child, th > :last-child {
+    margin-bottom: 0;
+  }
+
+  td, th {
+    border: 1px solid black;
+  }
+  </style>
+
+  <title></title>
+</head>
+
+<body>
+  <p>Test document</p>
+
+  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at lorem
+  augue, at molestie risus. Sed bibendum augue metus, sed cursus tortor. Aenean
+  semper consectetur pulvinar. Aliquam ultrices tempus nibh, ut mollis ligula
+  ultrices nec. Curabitur vel eros in mi mattis vulputate in nec lorem. Nam
+  auctor faucibus diam, eget accumsan lorem auctor eu. Maecenas imperdiet
+  tristique nisi. Sed sed metus lacus. In consectetur tempus justo, vitae porta
+  urna dapibus nec. Duis vitae lorem sit amet quam suscipit mollis eget non
+  orci. Praesent porta neque et mauris molestie nec sagittis nulla
+  volutpat.</p>
+
+  <h1 id="item2">Introduction</h1>
+
+  <p>Vivamus nec cursus massa. Aenean hendrerit sagittis volutpat. Donec diam
+  erat, vehicula at ultrices vel, aliquet ac mauris. Nam vitae lectus eu eros
+  sagittis sollicitudin. Mauris consequat, est suscipit feugiat eleifend, leo
+  erat rutrum dui, at volutpat metus metus vitae leo. Fusce dictum tincidunt
+  dignissim. Vestibulum eu est purus, eu aliquam quam. Aenean ultricies ante
+  sit amet libero sodales eu feugiat velit ornare.</p>
+
+  <h2 id="item3">Background</h2>
+
+  <p>Proin facilisis cursus elementum. Proin ac lorem ut odio ultricies
+  vehicula sit amet in diam. Proin ut nunc et nisl tristique sagittis. Aenean
+  aliquet eleifend enim non molestie. Vivamus tincidunt augue nec erat suscipit
+  ullamcorper. Nulla ornare risus odio. Nullam vestibulum tellus ac odio mattis
+  quis sollicitudin arcu interdum. Donec convallis malesuada ultricies. Sed
+  sodales porta commodo. Ut nec fringilla est. Nulla aliquet feugiat orci in
+  lobortis. Duis adipiscing aliquam orci, ac tempus leo posuere id. Nam neque
+  enim, faucibus id luctus ut, blandit eu est. Nullam non convallis mauris.</p>
+
+  <h2 id="item4">Motivation</h2>
+
+  <p>Nunc tincidunt, ante vel hendrerit cursus, lectus quam dapibus ipsum, eget
+  vestibulum odio turpis eleifend augue. Ut pharetra ultricies risus, id
+  gravida risus tincidunt eget. Nam eros massa, condimentum quis aliquet nec,
+  aliquam id enim. Integer diam justo, sagittis at faucibus eget, vestibulum id
+  lectus. Suspendisse pharetra lobortis diam sit amet fermentum. Donec nisl
+  ipsum, faucibus et bibendum a, viverra nec nunc. Cras vel arcu mauris. In hac
+  habitasse platea dictumst.</p>
+
+  <h2 id="item5">Project overview</h2>
+
+  <p>Donec sagittis dui sollicitudin massa congue et mollis nulla cursus.
+  Maecenas eget tempor risus. Nam euismod placerat ante viverra gravida. Mauris
+  nec arcu eget turpis accumsan vestibulum. Phasellus luctus, massa vel laoreet
+  faucibus, nulla tellus luctus ipsum, nec imperdiet lacus urna id diam. In
+  libero lacus, rutrum id rhoncus at, mollis consequat mauris. Ut et lectus
+  nulla, nec sagittis massa. Praesent tortor dui, elementum sed tempor eget,
+  porta vehicula ligula. Fusce aliquam lacus in ipsum tristique
+  pellentesque.</p>
+
+  <table style="width: 60%;" id="item16">
+    <caption>
+      A sample table
+    </caption>
+    <col width="50%">
+    <col width="50%">
+
+    <tbody>
+      <tr>
+        <td>
+          <p>Cell 1,1</p>
+        </td>
+
+        <td>
+          <p>Cell 1,2</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cell 2,1</p>
+        </td>
+
+        <td>
+          <p>Cell 2,2</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cell 3,1</p>
+        </td>
+
+        <td>
+          <p>Cell 3,2</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cell 4,1</p>
+        </td>
+
+        <td>
+          <p>Cell 4,2</p>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+
+  <p>In nisi felis, ornare nec feugiat at, sodales posuere nibh. Etiam suscipit
+  congue nunc, at sollicitudin est adipiscing viverra. Aenean sed augue quis
+  sem commodo pretium. Maecenas quis elit urna. Donec non arcu dui. Praesent
+  faucibus ornare purus id dignissim. Quisque dictum viverra orci id lacinia.
+  Etiam mollis egestas tortor, id iaculis augue malesuada non. Sed elementum
+  ornare quam, vel iaculis nibh vulputate facilisis.</p>
+
+  <p>Nunc sit amet ipsum tellus, ut laoreet magna. Phasellus consectetur, velit
+  vitae laoreet posuere, eros diam venenatis ante, quis dignissim turpis turpis
+  at quam. Cras ac justo quis nibh sollicitudin gravida. Vestibulum ac
+  vulputate dui. Suspendisse ac nulla mauris, eget condimentum nulla. Nullam
+  mollis metus sed magna facilisis ac accumsan est facilisis. Pellentesque
+  consequat tincidunt sapien in vehicula.</p>
+
+  <h1 id="item6">Implementation</h1>
+
+  <h2 id="item7">Phase One</h2>
+
+  <p>Phasellus dignissim ultricies mauris placerat molestie. Nunc sed orci nec
+  orci mollis suscipit. Maecenas eget quam non arcu dapibus volutpat. Quisque
+  ac turpis ut libero interdum tristique id in quam. Praesent eros velit,
+  dictum eu auctor ut, lobortis ac sem. Duis ipsum neque, volutpat id blandit
+  sed, tempor a dui. Sed ut magna ligula, et sagittis nunc. Phasellus at
+  eleifend orci. Quisque non nunc ipsum. Curabitur eu erat nec ante suscipit
+  mollis. Fusce dictum laoreet volutpat. Vivamus rutrum luctus mattis.</p>
+
+  <p>Sed augue velit, eleifend sed auctor sed, consectetur quis augue. Nulla
+  consectetur imperdiet quam et elementum. Praesent suscipit magna id diam
+  cursus in faucibus arcu semper. Phasellus pretium, nisl in sagittis viverra,
+  arcu tellus aliquam urna, et scelerisque eros lorem et diam. In ut nunc vel
+  nisi imperdiet mattis quis at massa. Phasellus quis tortor est. Sed ac
+  blandit eros. Curabitur ante mauris, condimentum in tempus sit amet, accumsan
+  ac leo. Ut quis tincidunt nunc. Vestibulum ante ipsum primis in faucibus orci
+  luctus et ultrices posuere cubilia Curae; Curabitur tincidunt, nisl id
+  interdum fringilla, mauris tortor volutpat libero, et consectetur purus magna
+  quis nibh.</p>
+
+  <h2 id="item8">Phase Two</h2>
+
+  <p>Aliquam dapibus tincidunt purus in aliquet. In sed ultricies sapien. Cras
+  risus nulla, ultrices ut vulputate ac, luctus in purus. Maecenas at lorem
+  sem, a vestibulum sem. Donec ante nisl, facilisis vel convallis vel, blandit
+  quis turpis. Sed id erat vitae metus cursus consectetur. Integer ac dapibus
+  dui. Nam mi ante, sollicitudin eu fringilla quis, fringilla nec lorem.
+  Aliquam ut nisi accumsan odio pulvinar euismod quis ac libero. Curabitur sit
+  amet ultrices risus. Class aptent taciti sociosqu ad litora torquent per
+  conubia nostra, per inceptos himenaeos. Nulla eu dui ut est aliquet iaculis
+  accumsan et leo. Donec dignissim lorem non arcu hendrerit vel feugiat quam
+  accumsan. Etiam mollis fermentum mi vel egestas. Cum sociis natoque penatibus
+  et magnis dis parturient montes, nascetur ridiculus mus.</p>
+
+  <p>Ut facilisis leo nec neque tempus a molestie libero consequat. Duis et
+  justo eu lorem accumsan eleifend sed nec quam. Duis a ligula ante. Donec
+  egestas lacus id mi convallis ut ullamcorper lorem consequat. Curabitur quis
+  sapien vel odio sodales consequat. Maecenas eget commodo eros. In hac
+  habitasse platea dictumst. Donec commodo venenatis consequat. Nulla
+  vestibulum adipiscing nulla id adipiscing. Nam congue, enim et lobortis
+  rhoncus, urna purus tempor magna, a eleifend mi nisl eu magna. Vestibulum
+  ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia
+  Curae;</p>
+
+  <h2 id="item9">Phase Three</h2>
+
+  <p>Proin placerat sapien eu odio ornare eu pharetra nunc lacinia. Duis tellus
+  nisl, condimentum eget tristique sit amet, imperdiet id felis. Nunc at lectus
+  non risus tristique sollicitudin. Etiam at tellus vitae velit sagittis
+  aliquam. Vivamus bibendum pellentesque dictum. Ut auctor interdum congue.
+  Cras ultrices sem sed sem convallis viverra.</p>
+
+  <p>Nunc pulvinar, diam quis dictum gravida, nulla augue sodales lectus, id
+  pharetra leo purus nec augue. Cum sociis natoque penatibus et magnis dis
+  parturient montes, nascetur ridiculus mus. Praesent consequat venenatis justo
+  tincidunt semper. Praesent egestas, ipsum id pharetra lobortis, arcu risus
+  viverra dui, nec sollicitudin augue leo et neque. Proin commodo pharetra
+  lacus, vitae lobortis libero posuere in. Vestibulum tellus ante, luctus quis
+  luctus at, laoreet feugiat turpis. Morbi commodo tellus non leo faucibus
+  ornare. Ut volutpat, diam et mollis dignissim, felis ante lobortis nibh, sed
+  ullamcorper nibh nunc sed dolor. Phasellus viverra leo erat, luctus vehicula
+  dui. Mauris quis ipsum mollis odio accumsan consectetur lacinia feugiat
+  risus. Pellentesque habitant morbi tristique senectus et netus et malesuada
+  fames ac turpis egestas. Fusce vel lectus non risus facilisis suscipit vitae
+  vitae velit. Fusce lacinia enim dapibus mauris porta luctus. Vivamus
+  venenatis sodales nunc non porttitor. Sed posuere commodo consectetur.</p>
+
+  <h1 id="item10">Required resources</h1>
+
+  <p>Vestibulum suscipit posuere elementum. Nullam volutpat, sapien at eleifend
+  congue, dolor sapien pulvinar nibh, eu vulputate velit urna quis nisl.
+  Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
+  cubilia Curae; Nunc auctor libero sed metus dictum quis placerat elit
+  varius.</p>
+
+  <h2 id="item11">Equipment</h2>
+
+  <p>Praesent fermentum augue sem. Cum sociis natoque penatibus et magnis dis
+  parturient montes, nascetur ridiculus mus. Fusce non lorem ligula, ac rhoncus
+  odio. Fusce ac magna lectus. Integer iaculis congue quam, sit amet tincidunt
+  orci mattis quis. Maecenas tempor, turpis nec euismod bibendum, orci dui
+  suscipit purus, iaculis mattis nunc magna at dui. Cras non neque tellus.
+  Integer lobortis, elit ac pretium imperdiet, nulla metus tempus nulla, vitae
+  bibendum diam nisl sed tellus. Class aptent taciti sociosqu ad litora
+  torquent per conubia nostra, per inceptos himenaeos.</p>
+
+  <p>Aliquam vehicula magna pharetra tortor pellentesque vestibulum. Vivamus ut
+  ullamcorper ante. Integer eu auctor lorem. Morbi sapien erat, viverra vitae
+  gravida id, bibendum eu augue. Maecenas nec dolor augue. Lorem ipsum dolor
+  sit amet, consectetur adipiscing elit. Donec aliquet dui at odio lacinia
+  placerat. Mauris a ipsum justo, id faucibus risus.</p>
+
+  <p>Sed vitae elit sed lectus varius vehicula. Maecenas pulvinar laoreet
+  metus, quis dignissim ipsum hendrerit fringilla. Quisque in neque sed ipsum
+  eleifend tempor. Etiam at posuere neque. Maecenas dapibus lacus tincidunt
+  neque elementum sed porta mauris luctus. Donec sit amet libero augue, at
+  hendrerit odio. Nulla consectetur, sem a vestibulum viverra, est nisl congue
+  leo, eget consectetur turpis justo et dolor. Fusce mollis mollis dui, eget
+  aliquet enim sollicitudin sed. Proin dictum sollicitudin rutrum. Curabitur
+  lorem risus, tempus ac ultricies id, suscipit ac nisl. Duis ultricies
+  facilisis arcu, vel congue risus tincidunt sit amet.</p>
+
+  <h2 id="item13">Personnel</h2>
+
+  <p>Etiam condimentum neque non dolor faucibus eu commodo nibh sodales.
+  Vivamus tempus est in risus malesuada vitae gravida nulla tristique. Maecenas
+  vitae justo a enim imperdiet euismod. Pellentesque porttitor metus nec enim
+  fermentum accumsan. Duis gravida ultricies aliquet. Etiam a risus turpis, sed
+  consequat arcu. Proin cursus quam non leo rutrum molestie. Ut eu orci ac nisl
+  lobortis porttitor a at massa. Nam id fringilla enim. Aenean pellentesque
+  molestie dui, sed dignissim urna mollis in. Ut ut metus non leo pharetra
+  tempor eu molestie metus. Aliquam iaculis nulla eget nisl ullamcorper vel
+  varius erat pretium.</p>
+
+  <p>Phasellus at magna tortor, eu elementum ligula. Etiam malesuada vehicula
+  elementum. Donec quis blandit dui. Phasellus tincidunt ullamcorper pharetra.
+  Integer egestas elementum egestas. Phasellus porta, neque a ultricies
+  pharetra, elit leo sodales purus, non auctor quam magna sed lectus. In et
+  ligula ipsum. Morbi vehicula auctor dolor cursus elementum. Cras vestibulum,
+  enim quis luctus posuere, metus enim mollis libero, at dictum enim magna eget
+  dolor. Vestibulum sagittis mi ac nibh dignissim placerat. Praesent vehicula
+  facilisis luctus. Donec ultrices, est non convallis lacinia, diam neque
+  blandit est, sed tincidunt felis ante sed dolor. Fusce laoreet justo sed
+  neque congue scelerisque.</p>
+
+  <h1 id="item14">Summary</h1>
+
+  <p>Nulla vitae ipsum orci. Suspendisse potenti. In sagittis quam non augue
+  blandit dapibus. Nulla dignissim viverra ante a egestas. In augue mi, porta
+  sit amet tempus eget, venenatis ac purus. Pellentesque non sapien et quam
+  molestie consectetur at ut magna. Maecenas turpis justo, adipiscing eu
+  tincidunt vulputate, ultricies sit amet magna.</p>
+
+  <p>Maecenas eget felis at massa pellentesque blandit ac eget lectus. Ut sit
+  amet nibh nunc, sit amet consequat massa. Suspendisse sit amet tempor tellus.
+  Vivamus nec lectus metus. Morbi id nibh neque. Pellentesque semper, sapien id
+  suscipit tincidunt, eros velit rhoncus dolor, non sagittis turpis erat vitae
+  velit. Nulla ligula turpis, lacinia non consequat in, lobortis sollicitudin
+  felis. Suspendisse pulvinar est eu felis congue id vehicula est luctus.</p>
+</body>
+</html>
diff --git a/consumers/corinthia/src/CMakeLists.txt b/consumers/corinthia/src/CMakeLists.txt
new file mode 100644
index 0000000..ef4b5ae
--- /dev/null
+++ b/consumers/corinthia/src/CMakeLists.txt
@@ -0,0 +1,87 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+
+###
+## global definitions
+###
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
+
+
+###
+## group source objects
+###
+set(SOURCES
+    Editor.h
+    Editor.cpp
+    JSInterface.h
+    JSInterface.cpp
+    main.cpp
+    MainWindow.h
+    MainWindow.cpp
+    Toolbar.h
+    Toolbar.cpp)
+#set(UI_SOURCES
+#    desktop.ui)
+
+
+
+###
+# Common include for all platform files
+###
+include_directories()
+include_directories(SYSTEM ${INCLUDE_DIRS})
+include_directories(.)
+link_directories(${LIB_DIRS})
+
+
+
+###
+## Qt magic
+###
+set(CMAKE_PREFIX_PATH         "/usr/local/opt/qt5")
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_AUTOMOC             ON)
+
+find_package(Qt5Widgets REQUIRED)
+find_package(Qt5WebKit REQUIRED)
+find_package(Qt5WebKitWidgets REQUIRED)
+include_directories("/usr/local/opt/qt5/include")
+
+qt5_wrap_ui(UI_HEADERS ${UI_SOURCES})
+source_group("Generated UI Headers" FILES ${UI_HEADERS})
+
+
+
+
+###
+# executable (release artifact)
+###
+add_executable(corinthia ${SOURCES} ${UI_HEADERS} ${UI_FILES})
+qt5_use_modules(corinthia Widgets WebKit WebKitWidgets)
+target_link_libraries(corinthia DocFormats ${LIBS})
+source_group(src FILES ${SOURCES})
+set_property(TARGET corinthia PROPERTY FOLDER consumers)
+
+message(CMAKE_SOURCE_DIR " is " ${CMAKE_SOURCE_DIR})
+message(TARGET_FILE_DIR ":corinthia is " $<TARGET_FILE_DIR:corinthia>)
+message(CMAKE_BINARY_DIR " is " ${CMAKE_BINARY_DIR})
+
+add_custom_command(TARGET corinthia PRE_BUILD
+                   COMMAND ${CMAKE_COMMAND} -E copy_directory
+                   ${CMAKE_SOURCE_DIR}/Editor/src ${CMAKE_BINARY_DIR}/share/corinthia/js)
+add_custom_command(TARGET corinthia PRE_BUILD
+                   COMMAND ${CMAKE_COMMAND} -E copy_directory
+                   ${CMAKE_SOURCE_DIR}/consumers/corinthia/res ${CMAKE_BINARY_DIR}/share/corinthia)
diff --git a/consumers/corinthia/src/Editor.cpp b/consumers/corinthia/src/Editor.cpp
new file mode 100644
index 0000000..9cce7b8
--- /dev/null
+++ b/consumers/corinthia/src/Editor.cpp
@@ -0,0 +1,296 @@
+// 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.
+
+#include "Editor.h"
+#include "JSInterface.h"
+#include <QWebView>
+#include <QWebFrame>
+#include <QFile>
+#include <QLayout>
+#include <QBoxLayout>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QCoreApplication>
+
+class EditorJSCallbacks : public JSCallbacks
+{
+public:
+    EditorJSCallbacks(Editor *editor) : _editor(editor) {}
+    void debug(const QString &message);
+    void addOutlineItem(const QString &itemId, const QString &type, const QString &title);
+    void updateOutlineItem(const QString &itemId, const QString &title);
+    void removeOutlineItem(const QString &itemId);
+    void outlineUpdated();
+    void setCursor(int x, int y, int width, int height);
+    void setSelectionHandles(int x1, int y1, int height1, int x2, int y2, int height2);
+    void setTableSelection(int x, int y, int width, int height);
+    void setSelectionBounds(int left, int top, int right, int bottom);
+    void clearSelectionHandlesAndCursor();
+    void updateAutoCorrect();
+    void error(const QString &message, const QString &operation);
+//private:
+    Editor *_editor;
+};
+
+class EditorJSEvaluator : public JSEvaluator
+{
+public:
+    EditorJSEvaluator(QWebView *webView, JSCallbacks *callbacks) : _webView(webView), _callbacks(callbacks) {}
+    virtual QString evaluate(const QString &script);
+    virtual JSCallbacks *callbacks() { return _callbacks; }
+private:
+    QWebView *_webView;
+    JSCallbacks *_callbacks;
+};
+
+class EditorPrivate : public QObject
+{
+    Q_OBJECT
+public:
+    EditorPrivate(Editor *editor);
+    virtual ~EditorPrivate();
+    public slots:
+    void webViewloadFinished(bool ok);
+public:
+
+    Editor *_editor;
+    QWebView *_webView;
+    EditorJSCallbacks *_callbacks;
+    EditorJSEvaluator *_evaluator;
+    JSInterface *_js;
+};
+
+
+
+const char *jsSources[] = {
+    "first.js",
+    "ElementTypes.js",
+    "AutoCorrect.js",
+    "ChangeTracking.js",
+    "Clipboard.js",
+    "Cursor.js",
+    "DOM.js",
+    "Editor.js",
+    "Equations.js",
+    "Figures.js",
+    "Formatting.js",
+    "Hierarchy.js",
+    "Input.js",
+    "Lists.js",
+    "Main.js",
+    "Metadata.js",
+    "NodeSet.js",
+    "Outline.js",
+    "Position.js",
+    "PostponedActions.js",
+    "Preview.js",
+    "Range.js",
+    "Scan.js",
+    "Selection.js",
+    "StringBuilder.js",
+    "Styles.js",
+    "Tables.js",
+    "Text.js",
+    "traversal.js",
+    "types.js",
+    "UndoManager.js",
+    "util.js",
+    "Viewport.js",
+    NULL,
+};
+
+
+
+
+void EditorJSCallbacks::debug(const QString &message)
+{
+    qStdOut() << "CB debug \"" << message << "\"" << endl;
+}
+
+void EditorJSCallbacks::addOutlineItem(const QString &itemId, const QString &type, const QString &title)
+{
+    qStdOut() << "CB addOutlineItem " << itemId << " " << type << " \"" << title << "\"" << endl;
+}
+
+void EditorJSCallbacks::updateOutlineItem(const QString &itemId, const QString &title)
+{
+    qStdOut() << "CB updateOutlineItem " << itemId << " \"" << title << "\"" << endl;
+}
+
+void EditorJSCallbacks::removeOutlineItem(const QString &itemId)
+{
+    qStdOut() << "CB removeOutlineItem " << itemId << endl;
+}
+
+void EditorJSCallbacks::outlineUpdated()
+{
+    qStdOut() << "CB outlineUpdated" << endl;
+}
+
+void EditorJSCallbacks::setCursor(int x, int y, int width, int height)
+{
+    qStdOut() << "CB setCursor " << x << " " << y << " " << width << " " << height << endl;
+}
+
+void EditorJSCallbacks::setSelectionHandles(int x1, int y1, int height1, int x2, int y2, int height2)
+{
+    qStdOut() << "CB setSelectionHandles " << x1 << " " << y1 << " " << height1 << " "
+    << x2 << " " << y2 << " " << height2 << endl;
+}
+
+void EditorJSCallbacks::setTableSelection(int x, int y, int width, int height)
+{
+    qStdOut() << "CB setTableSelection" << x << " " << y << " " << width << " " << height << endl;
+}
+
+void EditorJSCallbacks::setSelectionBounds(int left, int top, int right, int bottom)
+{
+    qStdOut() << "CB setSelectionBounds " << left << " " << top << " " << right << " " << bottom << endl;
+}
+
+void EditorJSCallbacks::clearSelectionHandlesAndCursor()
+{
+    qStdOut() << "CB clearSelectionHandlesAndCursor" << endl;
+}
+
+void EditorJSCallbacks::updateAutoCorrect()
+{
+    qStdOut() << "CB updateAutoCorrect" << endl;
+}
+
+void EditorJSCallbacks::error(const QString &message, const QString &operation)
+{
+    qStdOut() << "CB error \"" << message << "\" \"" << operation << "\"" << endl;
+}
+
+QString EditorJSEvaluator::evaluate(const QString &script)
+{
+    QWebFrame *frame = _webView->page()->mainFrame();
+    QVariant result = frame->evaluateJavaScript(script);
+    if (result.userType() != QMetaType::QString)
+        return QString::null;
+    else
+        return result.toString();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+EditorPrivate::EditorPrivate(Editor *editor) : _editor(editor)
+{
+    _webView = new QWebView(editor);
+    _callbacks = new EditorJSCallbacks(editor);
+    _evaluator = new EditorJSEvaluator(_webView,_callbacks);
+    _js = new JSInterface(_evaluator);
+    QObject::connect(_webView,SIGNAL(loadFinished(bool)),this,SLOT(webViewloadFinished(bool)));
+}
+
+EditorPrivate::~EditorPrivate()
+{
+    delete _webView;
+    delete _callbacks;
+    delete _evaluator;
+    delete _js;
+}
+
+void EditorPrivate::webViewloadFinished(bool ok)
+{
+    qStdOut() << "webViewloadFinished: ok = " << ok << endl;
+    if (!ok)
+        return;
+    QWebFrame *frame = _editor->webView()->page()->mainFrame();
+    //    frame->evaluateJavaScript("alert('This is a test')");
+
+    QString appPath = QCoreApplication::applicationDirPath();
+    QString baseDir = appPath + "/../share/corinthia/js";
+    baseDir = QUrl::fromLocalFile(baseDir).path();
+    qStdOut() << "js base dir = " << baseDir << endl;
+
+    for (int i = 0; jsSources[i] != NULL; i++) {
+        QString fullPath = baseDir + "/" + QString(jsSources[i]);
+        QFile file(fullPath);
+        if (file.open(QFile::ReadOnly)) {
+            QTextStream stream(&file);
+            QString content = stream.readAll();
+            frame->evaluateJavaScript(content);
+        }
+        else {
+            qStdOut() << "Can't open file " << fullPath << endl;
+            return;
+        }
+    }
+
+    frame->evaluateJavaScript("Main_init()");
+
+    processCallbacks(_evaluator);
+}
+
+Editor::Editor(QWidget *parent, Qt::WindowFlags f) : QWidget(parent,f)
+{
+    _p = new EditorPrivate(this);
+    QVBoxLayout *layout = new QVBoxLayout(this);
+    layout->addWidget(_p->_webView);
+    setLayout(layout);
+}
+
+Editor::~Editor()
+{
+    delete _p;
+}
+
+QWebView *Editor::webView() const
+{
+    return _p->_webView;
+}
+
+JSInterface *Editor::js() const
+{
+    return _p->_js;
+}
+
+#include <Editor.moc>
diff --git a/consumers/corinthia/src/Editor.h b/consumers/corinthia/src/Editor.h
new file mode 100644
index 0000000..117a18d
--- /dev/null
+++ b/consumers/corinthia/src/Editor.h
@@ -0,0 +1,35 @@
+// 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.
+
+#import <QWidget>
+
+class Editor;
+class EditorPrivate;
+class QWebView;
+class JSInterface;
+
+class Editor : public QWidget
+{
+    Q_OBJECT
+public:
+    Editor(QWidget *parent = 0, Qt::WindowFlags f = 0);
+    virtual ~Editor();
+    QWebView *webView() const;
+    JSInterface *js() const;
+private:
+    EditorPrivate *_p;
+};
diff --git a/consumers/corinthia/src/JSInterface.cpp b/consumers/corinthia/src/JSInterface.cpp
new file mode 100644
index 0000000..f6b549f
--- /dev/null
+++ b/consumers/corinthia/src/JSInterface.cpp
@@ -0,0 +1,1307 @@
+// 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.
+
+#include "JSInterface.h"
+#include <QJsonDocument>
+#include <assert.h>
+
+QTextStream& qStdOut()
+{
+    static QTextStream ts( stdout );
+    return ts;
+}
+
+class JSArgs
+{
+public:
+    QString toString() const;
+    JSArgs &operator<<(int value);
+    JSArgs &operator<<(unsigned int value);
+    JSArgs &operator<<(double value);
+    JSArgs &operator<<(bool value);
+    JSArgs &operator<<(const char *value);
+    JSArgs &operator<<(const QString &value);
+    JSArgs &operator<<(const QJsonArray &value);
+    JSArgs &operator<<(const QJsonObject &value);
+    JSArgs &operator<<(const QJsonValue &value);
+    JSArgs &operator<<(const QRect &value);
+    JSArgs &operator<<(const QPoint &value);
+    JSArgs &operator<<(const QSize &value);
+    JSArgs &operator<<(const QMap<QString,QString> map);
+private:
+    QJsonArray _array;
+};
+
+QString JSArgs::toString() const
+{
+    QString argsStr = QJsonDocument(_array).toJson(QJsonDocument::Compact);
+    assert(argsStr.size() >= 2);
+    assert(argsStr[0] == '[');
+    assert(argsStr[argsStr.size()-1] == ']');
+    argsStr.remove(0,1);
+    argsStr.remove(argsStr.size()-1,1);
+    return argsStr;
+}
+
+JSArgs &JSArgs::operator<<(int value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(unsigned int value)
+{
+    _array.append((double)value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(double value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(bool value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const char *value)
+{
+    if (value == NULL)
+        _array.append(QJsonValue::Null);
+    else
+        _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QString &value)
+{
+    if (value.isNull())
+        _array.append(QJsonValue::Null);
+    else
+        _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QJsonArray &value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QJsonObject &value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QJsonValue &value)
+{
+    _array.append(value);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QRect &value)
+{
+    QJsonObject obj;
+    obj["x"] = QJsonValue(value.x());
+    obj["y"] = QJsonValue(value.y());
+    obj["width"] = QJsonValue(value.width());
+    obj["height"] = QJsonValue(value.height());
+    _array.append(obj);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QPoint &value)
+{
+    QJsonObject obj;
+    obj["x"] = QJsonValue(value.x());
+    obj["y"] = QJsonValue(value.y());
+    _array.append(obj);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QSize &value)
+{
+    QJsonObject obj;
+    obj["width"] = QJsonValue(value.width());
+    obj["height"] = QJsonValue(value.height());
+    _array.append(obj);
+    return *this;
+}
+
+JSArgs &JSArgs::operator<<(const QMap<QString,QString> map)
+{
+    QJsonObject obj;
+    QMapIterator<QString,QString> it(map);
+    while (it.hasNext()) {
+        it.next();
+        QString key = it.key();
+        QString value = it.value();
+        if (value.isNull())
+            obj[key] = QJsonValue::Null;
+        else
+            obj[key] = value;
+    }
+    _array.append(obj);
+    return *this;
+}
+
+void testargs()
+{
+    int intVal = 4294967295;
+    unsigned int uintVal = 4294967295;
+    QMap<QString,QString> map;
+    map["color"] = "red";
+    map["font-size"] = "24";
+    map["font-family"] = "Helvetica";
+    map["background-color"] = QString::null;
+    JSArgs args = JSArgs()
+    << intVal
+    << uintVal
+    << 3.2
+    << true
+    << false
+    << "test"
+    << (char *)NULL
+    << QString("test")
+    << QString::null
+    << QJsonArray()
+    << QJsonObject()
+    << QJsonValue("value")
+    << QRect(1,2,3,4)
+    << QPoint(5,6)
+    << QSize(7,8)
+    << map;
+    qStdOut() << args.toString() << endl;
+}
+
+QRect QRectFromJson(QJsonValue value)
+{
+    if (!value.isObject()) {
+        qStdOut() << "QRectFromJson: value is not an object" << endl;
+        return QRect();
+    }
+
+    QJsonObject obj = value.toObject();
+    QJsonValue x = obj["x"];
+    QJsonValue y = obj["y"];
+    QJsonValue width = obj["width"];
+    QJsonValue height = obj["height"];
+    if (!x.isDouble() || !y.isDouble() || !width.isDouble() || !height.isDouble()) {
+        qStdOut() << "QRectFromJson: invalid value(s)" << endl;
+        return QRect();
+    }
+
+    return QRect(x.toDouble(),y.toDouble(),width.toDouble(),height.toDouble());
+}
+
+QString QRectString(QRect rect)
+{
+    return QString().sprintf("(%d,%d,%d,%d)",rect.x(),rect.y(),rect.width(),rect.height());
+}
+
+void processCallbacks(JSEvaluator *evaluator)
+{
+    JSCallbacks *callbacks = evaluator->callbacks();
+
+    QString messagesStr = evaluator->evaluate("Editor_getBackMessages()");
+    if (messagesStr.isNull()) {
+        qStdOut() << "Editor_getBackMessages failed" << endl;
+        return;
+    }
+
+    //    QJsonDocument doc = QJsonDocument::fromVariant(var);
+    QJsonDocument doc = QJsonDocument::fromJson(messagesStr.toUtf8());
+    if (doc.isNull()) {
+        qStdOut() << "JSON parse failed" << endl;
+        return;
+    }
+
+    if (!doc.isArray()) {
+        qStdOut() << "JSON is not an array" << endl;
+        return;
+    }
+
+    qStdOut() << "JSON parse succeeded; top-level is an array with " << doc.array().size() << " items" << endl;
+    QJsonArray topArray = doc.array();
+    for (int i = 0; i < topArray.size(); i++) {
+        QJsonValue val = topArray.at(i);
+        if (!val.isArray()) {
+            qStdOut() << "Entry " << i << " is not an array" << endl;
+            return;
+        }
+        //        printf("entry %d: %s\n",i,qcstring(val.toString()));
+        QJsonArray array = val.toArray();
+        if (array.size() < 1) {
+            qStdOut() << "Callback array " << i << " is empty" << endl;
+            return;
+        }
+        if (!array.at(0).isString()) {
+            qStdOut() << "Callback array " << i << " does not start with a string" << endl;
+            return;
+        }
+        QString functionName = array.at(0).toString();
+
+        //        if (functionName == "addOutlineItem") {
+        //            qStdOut() << "cbName " << i << " = " << functionName << " *************************" << endl;
+        //        }
+        //        else {
+        //            qStdOut() << "cbName " << i << " = " << functionName << endl;
+        //        }
+
+        if ((functionName == "debug") &&
+            (array.size() == 2) &&
+            (array.at(1).isString())) {
+            callbacks->debug(array.at(1).toString());
+        }
+        else if ((functionName == "addOutlineItem") &&
+                 (array.size() == 4) &&
+                 (array.at(1).isString()) &&
+                 (array.at(2).isString()) &&
+                 ((array.at(3).isString()) || (array.at(3).isNull()))) {
+            callbacks->addOutlineItem(array.at(1).toString(),array.at(2).toString(),array.at(3).toString());
+        }
+        else if ((functionName == "updateOutlineItem") &&
+                 (array.size() == 3) &&
+                 array.at(1).isString() &&
+                 array.at(2).isString()) {
+            callbacks->updateOutlineItem(array.at(1).toString(),array.at(2).toString());
+        }
+        else if ((functionName == "removeOutlineItem") &&
+                 (array.size() == 2) &&
+                 array.at(1).isString()) {
+            callbacks->removeOutlineItem(array.at(1).toString());
+        }
+        else if ((functionName == "outlineUpdated") &&
+                 (array.size() == 1)) {
+            callbacks->outlineUpdated();
+        }
+        else if ((functionName == "setSelectionHandles") &&
+                 (array.size() == 7) &&
+                 array.at(1).isDouble() &&
+                 array.at(2).isDouble() &&
+                 array.at(3).isDouble() &&
+                 array.at(4).isDouble() &&
+                 array.at(5).isDouble() &&
+                 array.at(6).isDouble()) {
+            callbacks->setSelectionHandles(array.at(1).toDouble(),
+                                            array.at(2).toDouble(),
+                                            array.at(3).toDouble(),
+                                            array.at(4).toDouble(),
+                                            array.at(5).toDouble(),
+                                            array.at(6).toDouble());
+        }
+        else if ((functionName == "setTableSelection") &&
+                 (array.size() == 5) &&
+                 array.at(1).isDouble() &&
+                 array.at(2).isDouble() &&
+                 array.at(3).isDouble() &&
+                 array.at(4).isDouble()) {
+            callbacks->setTableSelection(array.at(1).toDouble(),
+                                          array.at(2).toDouble(),
+                                          array.at(3).toDouble(),
+                                          array.at(4).toDouble());
+        }
+        else if ((functionName == "setCursor") &&
+                 (array.size() == 5) &&
+                 array.at(1).isDouble() &&
+                 array.at(2).isDouble() &&
+                 array.at(3).isDouble() &&
+                 array.at(4).isDouble()) {
+            callbacks->setCursor(array.at(1).toDouble(),
+                                  array.at(2).toDouble(),
+                                  array.at(3).toDouble(),
+                                  array.at(4).toDouble());
+        }
+        else if ((functionName == "clearSelectionHandlesAndCursor") &&
+                 (array.size() == 1)) {
+            callbacks->clearSelectionHandlesAndCursor();
+        }
+        else if ((functionName == "setSelectionBounds") &&
+                 (array.size() == 5) &&
+                 array.at(1).isDouble() &&
+                 array.at(2).isDouble() &&
+                 array.at(3).isDouble() &&
+                 array.at(4).isDouble()) {
+            callbacks->setSelectionBounds(array.at(1).toDouble(),
+                                           array.at(2).toDouble(),
+                                           array.at(3).toDouble(),
+                                           array.at(4).toDouble());
+        }
+        else if ((functionName == "updateAutoCorrect") &&
+                 (array.size() == 1)) {
+            callbacks->updateAutoCorrect();
+        }
+        else if ((functionName == "error") &&
+                 (array.size() == 3) &&
+                 array.at(1).isString() &&
+                 array.at(2).isString()) {
+            callbacks->error(array.at(1).toString(),array.at(2).toString());
+        }
+        else {
+            qStdOut() << "INVALID CALLBACK OR ARGS: " << functionName << endl;
+        }
+    }
+}
+
+QJsonValue evaljsStr(JSEvaluator *ev, const QString &functionName, const QString &argsStr)
+{
+    QString script;
+    QTextStream stream(&script);
+    stream << "Main_execute(function() { return JSON.stringify({ result: ";
+    stream << functionName << "(";
+    stream << argsStr;
+    stream << ")}); });";
+
+    qStdOut() << "EVALUATE: " << script << endl;
+
+    QString resultStr = ev->evaluate(script);
+    qStdOut() << "RESULT: " << resultStr << endl;
+    processCallbacks(ev);
+    if (resultStr.isNull())
+        return QJsonValue(QJsonValue::Null);
+
+    QJsonDocument doc = QJsonDocument::fromJson(resultStr.toUtf8());
+    if (!doc.isObject()) {
+        ev->callbacks()->error("Error parsing returned JSON","evaluate");
+        return QJsonValue(QJsonValue::Null);
+    }
+
+    QJsonObject obj = doc.object();
+    if (!obj.contains("result")) {
+        return QJsonValue(QJsonValue::Null);
+        //        ev->callbacks()->error("Returned JSON does not contain a result","evaluate");
+        //        return QJsonValue(QJsonValue::Null);
+    }
+    
+    return obj["result"];
+}
+
+QJsonValue evaljs(JSEvaluator *ev, const QString &functionName, const JSArgs &args)
+{
+    return evaljsStr(ev,functionName,args.toString());
+}
+
+// Functions implemented in AutoCorrect.js
+
+void JSAutoCorrect::correctPrecedingWord(int numChars, const QString &replacement, bool confirmed)
+{
+    JSArgs args = JSArgs() << numChars << replacement << confirmed;
+    evaljs(_evaluator,"AutoCorrect_correctPrecedingWord",args);
+}
+
+QJsonObject JSAutoCorrect::getCorrection()
+{
+    QJsonValue result = evaljs(_evaluator,"AutoCorrect_getCorrection",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+QJsonObject JSAutoCorrect::getCorrectionCoords()
+{
+    QJsonValue result = evaljs(_evaluator,"AutoCorrect_getCorrectionCoords",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSAutoCorrect::acceptCorrection()
+{
+    evaljs(_evaluator,"AutoCorrect_acceptCorrection",JSArgs());
+}
+
+void JSAutoCorrect::replaceCorrection(const QString &replacement)
+{
+    JSArgs args = JSArgs() << replacement;
+    evaljs(_evaluator,"AutoCorrect_replaceCorrection",args);
+}
+
+// Functions implemented in ChangeTracking.js
+
+bool JSChangeTracking::showChanges()
+{
+    QJsonValue result = evaljs(_evaluator,"ChangeTracking_showChanges",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+bool JSChangeTracking::trackChanges()
+{
+    QJsonValue result = evaljs(_evaluator,"ChangeTracking_trackChanges",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+void JSChangeTracking::setShowChanges(bool showChanges)
+{
+    JSArgs args = JSArgs() << showChanges;
+    evaljs(_evaluator,"ChangeTracking_setShowChanges",args);
+}
+
+void JSChangeTracking::setTrackChanges(bool trackChanges)
+{
+    JSArgs args = JSArgs() << trackChanges;
+    evaljs(_evaluator,"ChangeTracking_setTrackChanges",args);
+}
+
+// Functions implemented in Clipboard.js
+
+QJsonObject JSClipboard::clipboardCut()
+{
+    QJsonValue result = evaljs(_evaluator,"Clipboard_cut",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+QJsonObject JSClipboard::clipboardCopy()
+{
+    QJsonValue result = evaljs(_evaluator,"Clipboard_copy",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSClipboard::pasteHTML(const QString &html)
+{
+    JSArgs args = JSArgs() << html;
+    evaljs(_evaluator,"Clipboard_pasteHTML",args);
+}
+
+void JSClipboard::pasteText(const QString &text)
+{
+    JSArgs args = JSArgs() << text;
+    evaljs(_evaluator,"Clipboard_pasteText",args);
+}
+
+// Functions implemented in Cursor.js
+
+
+QString JSCursor::positionCursor(int x, int y, bool wordBoundary)
+{
+    JSArgs args = JSArgs() << x << y << wordBoundary;
+    QJsonValue result = evaljs(_evaluator,"Cursor_positionCursor",args);
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QRect JSCursor::getCursorPosition()
+{
+    QJsonValue result = evaljs(_evaluator,"Cursor_getCursorPosition",JSArgs());
+    return QRectFromJson(result);
+}
+
+void JSCursor::moveLeft()
+{
+    evaljs(_evaluator,"Cursor_moveLeft",JSArgs());
+}
+
+void JSCursor::moveRight()
+{
+    evaljs(_evaluator,"Cursor_moveRight",JSArgs());
+}
+
+void JSCursor::moveToStartOfDocument()
+{
+    evaljs(_evaluator,"Cursor_moveToStartOfDocument",JSArgs());
+}
+
+void JSCursor::moveToEndOfDocument()
+{
+    evaljs(_evaluator,"Cursor_moveToEndOfDocument",JSArgs());
+}
+
+void JSCursor::insertReference(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    evaljs(_evaluator,"Cursor_insertReference",args);
+}
+
+void JSCursor::insertLink(const QString &text, const QString &url)
+{
+    JSArgs args = JSArgs() << text << url;
+    evaljs(_evaluator,"Cursor_insertLink",args);
+}
+
+void JSCursor::insertCharacter(unsigned short character, bool allowInvalidPos)
+{
+    JSArgs args = JSArgs() << QString(character) << allowInvalidPos;
+    evaljs(_evaluator,"Cursor_insertCharacter",args);
+}
+
+void JSCursor::deleteCharacter()
+{
+    evaljs(_evaluator,"Cursor_deleteCharacter",JSArgs());
+}
+
+void JSCursor::enterPressed()
+{
+    evaljs(_evaluator,"Cursor_enterPressed",JSArgs());
+}
+
+QString JSCursor::getPrecedingWord()
+{
+    QJsonValue result = evaljs(_evaluator,"Cursor_getPrecedingWord",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QJsonObject JSCursor::getLinkProperties()
+{
+    QJsonValue result = evaljs(_evaluator,"Cursor_getLinkProperties",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSCursor::setLinkProperties(QJsonObject properties)
+{
+    JSArgs args = JSArgs() << properties;
+    evaljs(_evaluator,"Cursor_setLinkProperties",args);
+}
+
+void JSCursor::setReferenceTarget(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    evaljs(_evaluator,"Cursor_setReferenceTarget",args);
+}
+
+void JSCursor::insertFootnote(const QString &content)
+{
+    JSArgs args = JSArgs() << content;
+    evaljs(_evaluator,"Cursor_insertFootnote",args);
+}
+
+void JSCursor::insertEndnote(const QString &content)
+{
+    JSArgs args = JSArgs() << content;
+    evaljs(_evaluator,"Cursor_insertEndnote",args);
+}
+
+// Functions implemented in Equations.js
+
+void JSEquations::insertEquation()
+{
+    evaljs(_evaluator,"Equations_insertEquation",JSArgs());
+}
+
+// Functions implemented in Figures.js
+
+void JSFigures::insertFigure(const QString &filename, const QString &width,
+                             bool numbered, const QString &caption)
+{
+    JSArgs args = JSArgs() << filename << width << numbered << caption;
+    evaljs(_evaluator,"Figures_insertFigure",args);
+}
+
+QString JSFigures::getSelectedFigureId()
+{
+    QJsonValue result = evaljs(_evaluator,"Figures_getSelectedFigureId",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QJsonObject JSFigures::getProperties(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    QJsonValue result = evaljs(_evaluator,"Figures_getProperties",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSFigures::setProperties(const QString &itemId, const QString &width, const QString &src)
+{
+    JSArgs args = JSArgs() << itemId << width << src;
+    evaljs(_evaluator,"Figures_setProperties",args);
+}
+
+QJsonObject JSFigures::getGeometry(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    QJsonValue result = evaljs(_evaluator,"Figures_getGeometry",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+// Functions implemented in Formatting.js
+
+QJsonObject JSFormatting::getFormatting()
+{
+    QJsonValue result = evaljs(_evaluator,"Formatting_getFormatting",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSFormatting::applyFormattingChanges(const QString &style, QJsonObject properties)
+{
+    JSArgs args = JSArgs() << style << properties;
+    evaljs(_evaluator,"Formatting_applyFormattingChanges",args);
+}
+
+// Functions implemented in Input.js
+
+void JSInput::removePosition(int posId)
+{
+    JSArgs args = JSArgs() << posId;
+    evaljs(_evaluator,"Input_removePosition",args);
+}
+
+QString JSInput::textInRange(int startId, int startAdjust, int endId, int endAdjust)
+{
+    JSArgs args = JSArgs() << startId << startAdjust << endId << endAdjust;
+    QJsonValue result = evaljs(_evaluator,"Input_textInRange",args);
+    return result.isString() ? result.toString() : QString::null;
+}
+
+void JSInput::replaceRange(int startId, int endId, const QString &text)
+{
+    JSArgs args = JSArgs() << startId << endId << text;
+    evaljs(_evaluator,"Input_replaceRange",args);
+}
+
+QJsonObject JSInput::selectedTextRange()
+{
+    QJsonValue result = evaljs(_evaluator,"Input_selectedTextRange",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSInput::setSelectedTextRange(int startId, int endId)
+{
+    JSArgs args = JSArgs() << startId << endId;
+    evaljs(_evaluator,"Input_setSelectedTextRange",args);
+}
+
+QJsonObject JSInput::markedTextRange()
+{
+    QJsonValue result = evaljs(_evaluator,"Input_markedTextRange",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSInput::setMarkedText(const QString &text, int startOffset, int endOffset)
+{
+    JSArgs args = JSArgs() << text << startOffset << endOffset;
+    evaljs(_evaluator,"Input_setMarkedText",args);
+}
+
+void JSInput::unmarkText()
+{
+    evaljs(_evaluator,"Input_unmarkText",JSArgs());
+}
+
+bool JSInput::forwardSelectionAffinity()
+{
+    QJsonValue result = evaljs(_evaluator,"Input_forwardSelectionAffinity",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+void JSInput::setForwardSelectionAffinity(bool forwardSelectionAffinity)
+{
+    JSArgs args = JSArgs() << forwardSelectionAffinity;
+    evaljs(_evaluator,"Input_setForwardSelectionAffinity",args);
+}
+
+int JSInput::positionFromPositionOffset(int posId, int offset)
+{
+    JSArgs args = JSArgs() << posId << offset;
+    QJsonValue result = evaljs(_evaluator,"Input_positionFromPositionOffset",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::positionFromPositionInDirectionOffset(int posId, const QString &direction, int offset)
+{
+    JSArgs args = JSArgs() << posId << direction << offset;
+    QJsonValue result = evaljs(_evaluator,"Input_positionFromPositionInDirectionOffset",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::comparePositionToPosition(int positionId, int otherId)
+{
+    JSArgs args = JSArgs() << positionId << otherId;
+    QJsonValue result = evaljs(_evaluator,"Input_comparePositionToPosition",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::offsetFromPositionToPosition(int fromPosition, int toPosition)
+{
+    JSArgs args = JSArgs() << fromPosition << toPosition;
+    QJsonValue result = evaljs(_evaluator,"Input_offsetFromPositionToPosition",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::positionWithinRangeFarthestInDirection(int startId, int endId, const QString &direction)
+{
+    JSArgs args = JSArgs() << startId << endId << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_positionWithinRangeFarthestInDirection",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+QJsonObject JSInput::characterRangeByExtendingPositionInDirection(int positionId, const QString &direction)
+{
+    JSArgs args = JSArgs() << positionId << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_characterRangeByExtendingPositionInDirection",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+QJsonObject JSInput::firstRectForRange(int startId, int endId)
+{
+    JSArgs args = JSArgs() << startId << endId;
+    QJsonValue result = evaljs(_evaluator,"Input_firstRectForRange",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+QJsonObject JSInput::caretRectForPosition(int posId)
+{
+    JSArgs args = JSArgs() << posId;
+    QJsonValue result = evaljs(_evaluator,"Input_caretRectForPosition",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+int JSInput::closestPositionToPoint(int x, int y)
+{
+    JSArgs args = JSArgs() << x << y;
+    QJsonValue result = evaljs(_evaluator,"Input_closestPositionToPoint",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::closestPositionToPointWithinRange(int x, int y, int startId, int endId)
+{
+    JSArgs args = JSArgs() << x << y << startId << endId;
+    QJsonValue result = evaljs(_evaluator,"Input_closestPositionToPointWithinRange",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+QJsonObject JSInput::characterRangeAtPoint(int x, int y)
+{
+    JSArgs args = JSArgs() << x << y;
+    QJsonValue result = evaljs(_evaluator,"Input_characterRangeAtPoint",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+int JSInput::positionWithinRangeAtCharacterOffset(int startId, int endId, int offset)
+{
+    JSArgs args = JSArgs() << startId << endId << offset;
+    QJsonValue result = evaljs(_evaluator,"Input_positionWithinRangeAtCharacterOffset",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSInput::characterOffsetOfPositionWithinRange(int positionId, int startId, int endId)
+{
+    JSArgs args = JSArgs() << positionId << startId << endId;
+    QJsonValue result = evaljs(_evaluator,"Input_characterOffsetOfPositionWithinRange",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+bool JSInput::isPositionAtBoundaryGranularityInDirection(int posId, const QString &granularity,
+                                                         const QString &direction)
+{
+    JSArgs args = JSArgs() << posId << granularity << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_isPositionAtBoundaryGranularityInDirection",args);
+    return result.isBool() ? result.toBool() : false;
+}
+
+bool JSInput::isPositionWithinTextUnitInDirection(int posId, const QString &granularity,
+                                                  const QString &direction)
+{
+    JSArgs args = JSArgs() << posId << granularity << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_isPositionWithinTextUnitInDirection",args);
+    return result.isBool() ? result.toBool() : false;
+}
+
+int JSInput::positionFromPositionToBoundaryInDirection(int posId, const QString &granularity,
+                                                       const QString &direction)
+{
+    JSArgs args = JSArgs() << posId << granularity << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_positionFromPositionToBoundaryInDirection",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+QJsonObject JSInput::rangeEnclosingPositionWithGranularityInDirection(int posId,
+                                                                      const QString &granularity,
+                                                                      const QString &direction)
+{
+    JSArgs args = JSArgs() << posId << granularity << direction;
+    QJsonValue result = evaljs(_evaluator,"Input_rangeEnclosingPositionWithGranularityInDirection",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+// Functions implemented in Lists.js
+
+void JSLists::increaseIndent()
+{
+    evaljs(_evaluator,"Lists_increaseIndent",JSArgs());
+}
+
+void JSLists::decreaseIndent()
+{
+    evaljs(_evaluator,"Lists_decreaseIndent",JSArgs());
+}
+
+void JSLists::clearList()
+{
+    evaljs(_evaluator,"Lists_clearList",JSArgs());
+}
+
+void JSLists::setUnorderedList()
+{
+    evaljs(_evaluator,"Lists_setUnorderedList",JSArgs());
+}
+
+void JSLists::setOrderedList()
+{
+    evaljs(_evaluator,"Lists_setOrderedList",JSArgs());
+}
+
+// Functions implemented in Main.js
+
+QString JSMain::getLanguage()
+{
+    QJsonValue result = evaljs(_evaluator,"Main_getLanguage",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+void JSMain::setLanguage(const QString &language)
+{
+    JSArgs args = JSArgs() << language;
+    evaljs(_evaluator,"Main_setLanguage",args);
+}
+
+QString JSMain::setGenerator(const QString &generator)
+{
+    JSArgs args = JSArgs() << generator;
+    QJsonValue result = evaljs(_evaluator,"Main_setGenerator",args);
+    return result.isString() ? result.toString() : QString::null;
+}
+
+bool JSMain::prepareForSave()
+{
+    QJsonValue result = evaljs(_evaluator,"Main_prepareForSave",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+QString JSMain::getHTML()
+{
+    QJsonValue result = evaljs(_evaluator,"Main_getHTML",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+bool JSMain::isEmptyDocument()
+{
+    QJsonValue result = evaljs(_evaluator,"Main_isEmptyDocument",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+// Functions implemented in Metadata.js
+
+QJsonObject JSMetadata::getMetadata()
+{
+    QJsonValue result = evaljs(_evaluator,"Metadata_getMetadata",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSMetadata::setMetadata(const QJsonObject &metadata)
+{
+    JSArgs args = JSArgs() << metadata;
+    evaljs(_evaluator,"Metadata_setMetadata",args);
+}
+
+// Functions implemented in Outline.js
+
+QJsonObject JSOutline::getOutline()
+{
+    QJsonValue result = evaljs(_evaluator,"Outline_getOutline",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSOutline::moveSection(const QString &sectionId, const QString &parentId, const QString &nextId)
+{
+    JSArgs args = JSArgs() << sectionId << parentId << nextId;
+    evaljs(_evaluator,"Outline_moveSection",args);
+}
+
+void JSOutline::deleteItem(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    evaljs(_evaluator,"Outline_deleteItem",args);
+}
+
+void JSOutline::goToItem(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    evaljs(_evaluator,"Outline_goToItem",args);
+}
+
+void JSOutline::scheduleUpdateStructure()
+{
+    evaljs(_evaluator,"Outline_scheduleUpdateStructure",JSArgs());
+}
+
+void JSOutline::setNumbered(const QString &itemId, bool numbered)
+{
+    JSArgs args = JSArgs() << itemId << numbered;
+    evaljs(_evaluator,"Outline_setNumbered",args);
+}
+
+void JSOutline::setTitle(const QString &itemId, const QString &title)
+{
+    JSArgs args = JSArgs() << itemId << title;
+    evaljs(_evaluator,"Outline_setTitle",args);
+}
+
+void JSOutline::insertTableOfContents()
+{
+    evaljs(_evaluator,"Outline_insertTableOfContents",JSArgs());
+}
+
+void JSOutline::insertListOfFigures()
+{
+    evaljs(_evaluator,"Outline_insertListOfFigures",JSArgs());
+}
+
+void JSOutline::insertListOfTables()
+{
+    evaljs(_evaluator,"Outline_insertListOfTables",JSArgs());
+}
+
+void JSOutline::setPrintMode(bool printMode)
+{
+    JSArgs args = JSArgs() << printMode;
+    evaljs(_evaluator,"Outline_setPrintMode",args);
+}
+
+QJsonObject JSOutline::examinePrintLayout(int pageHeight)
+{
+    JSArgs args = JSArgs() << pageHeight;
+    QJsonValue result = evaljs(_evaluator,"Outline_examinePrintLayout",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+bool JSOutline::detectSectionNumbering()
+{
+    QJsonValue result = evaljs(_evaluator,"Outline_detectSectionNumbering",JSArgs());
+    return result.isBool() ? result.toBool() : false;
+}
+
+QJsonObject JSOutline::findUsedStyles()
+{
+    QJsonValue result = evaljs(_evaluator,"Outline_findUsedStyles",JSArgs());
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+// Functions implemented in Preview.js
+
+void JSPreview::showForStyle(const QString &styleId, const QString &uiName, const QString &title)
+{
+    JSArgs args = JSArgs() << styleId << uiName << title;
+    evaljs(_evaluator,"Preview_showForStyle",args);
+    // TODO
+}
+
+// Functions implemented in Scan.js
+
+void JSScan::reset()
+{
+    evaljs(_evaluator,"Scan_reset",JSArgs());
+}
+
+EDScanParagraph *JSScan::next()
+{
+    // TODO
+    return NULL;
+}
+
+int JSScan::addMatch(int start, int end)
+{
+    JSArgs args = JSArgs() << start << end;
+    QJsonValue result = evaljs(_evaluator,"Scan_addMatch",args);
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+void JSScan::showMatch(int matchId)
+{
+    JSArgs args = JSArgs() << matchId;
+    evaljs(_evaluator,"Scan_showMatch",args);
+}
+
+void JSScan::replaceMatch(int matchId, const QString &text)
+{
+    JSArgs args = JSArgs() << matchId << text;
+    evaljs(_evaluator,"Scan_replaceMatch",args);
+}
+
+void JSScan::removeMatch(int matchId)
+{
+    JSArgs args = JSArgs() << matchId;
+    evaljs(_evaluator,"Scan_removeMatch",args);
+}
+
+void JSScan::goToMatch(int matchId)
+{
+    JSArgs args = JSArgs() << matchId;
+    evaljs(_evaluator,"Scan_goToMatch",args);
+}
+
+// Functions implemented in Selection.js
+
+void JSSelection::update()
+{
+    evaljs(_evaluator,"Selection_update",JSArgs());
+}
+
+void JSSelection::selectAll()
+{
+    evaljs(_evaluator,"Selection_selectAll",JSArgs());
+}
+
+void JSSelection::selectParagraph()
+{
+    evaljs(_evaluator,"Selection_selectParagraph",JSArgs());
+}
+
+void JSSelection::selectWordAtCursor()
+{
+    evaljs(_evaluator,"Selection_selectWordAtCursor",JSArgs());
+}
+
+QString JSSelection::dragSelectionBegin(int x, int y, bool selectWord)
+{
+    JSArgs args = JSArgs() << x << y << selectWord;
+    QJsonValue result = evaljs(_evaluator,"Selection_dragSelectionBegin",args);
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QString JSSelection::dragSelectionUpdate(int x, int y, bool selectWord)
+{
+    JSArgs args = JSArgs() << x << y << selectWord;
+    QJsonValue result = evaljs(_evaluator,"Selection_dragSelectionUpdate",args);
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QString JSSelection::moveStartLeft()
+{
+    QJsonValue result = evaljs(_evaluator,"Selection_moveStartLeft",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QString JSSelection::moveStartRight()
+{
+    QJsonValue result = evaljs(_evaluator,"Selection_moveStartRight",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QString JSSelection::moveEndLeft()
+{
+    QJsonValue result = evaljs(_evaluator,"Selection_moveEndLeft",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QString JSSelection::moveEndRight()
+{
+    QJsonValue result = evaljs(_evaluator,"Selection_moveEndRight",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+void JSSelection::setSelectionStartAtCoords(int x, int y)
+{
+    JSArgs args = JSArgs() << x << y;
+    evaljs(_evaluator,"Selection_setSelectionStartAtCoords",args);
+}
+
+void JSSelection::setSelectionEndAtCoords(int x, int y)
+{
+    JSArgs args = JSArgs() << x << y;
+    evaljs(_evaluator,"Selection_setSelectionEndAtCoords",args);
+}
+
+void JSSelection::setTableSelectionEdgeAtCoords(const QString &edge, int x, int y)
+{
+    JSArgs args = JSArgs() << edge << x << y;
+    evaljs(_evaluator,"Selection_setTableSelectionEdgeAtCoords",args);
+}
+
+void JSSelection::print()
+{
+    evaljs(_evaluator,"Selection_print",JSArgs());
+}
+
+// Functions implemented in Styles.js
+
+QString JSStyles::getCSSText()
+{
+    QJsonValue result = evaljs(_evaluator,"Styles_getCSSText",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+void JSStyles::setCSSText(const QString &cssText, const QJsonObject &rules)
+{
+    JSArgs args = JSArgs() << cssText << rules;
+    evaljs(_evaluator,"Styles_setCSSText",args);
+}
+
+QString JSStyles::paragraphClass()
+{
+    QJsonValue result = evaljs(_evaluator,"Styles_getParagraphClass",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+void JSStyles::setParagraphClass(const QString &paragraphClass)
+{
+    JSArgs args = JSArgs() << paragraphClass;
+    evaljs(_evaluator,"Styles_setParagraphClass",args);
+}
+
+// Functions implemented in Tables.js
+
+void JSTables::insertTable(int rows, int cols, const QString &width, bool numbered,
+                           const QString &caption, const QString &className)
+{
+    JSArgs args = JSArgs() << rows << cols << width << numbered << caption << className;
+    evaljs(_evaluator,"Tables_insertTable",args);
+}
+
+void JSTables::addAdjacentRow()
+{
+    evaljs(_evaluator,"Tables_addAdjacentRow",JSArgs());
+}
+
+void JSTables::addAdjacentColumn()
+{
+    evaljs(_evaluator,"Tables_addAdjacentColumn",JSArgs());
+}
+
+void JSTables::removeAdjacentRow()
+{
+    evaljs(_evaluator,"Tables_removeAdjacentRow",JSArgs());
+}
+
+void JSTables::removeAdjacentColumn()
+{
+    evaljs(_evaluator,"Tables_removeAdjacentColumn",JSArgs());
+}
+
+void JSTables::clearCells()
+{
+    evaljs(_evaluator,"Tables_clearCells",JSArgs());
+}
+
+void JSTables::mergeCells()
+{
+    evaljs(_evaluator,"Tables_mergeCells",JSArgs());
+}
+
+void JSTables::splitSelection()
+{
+    evaljs(_evaluator,"Tables_splitSelection",JSArgs());
+}
+
+QString JSTables::getSelectedTableId()
+{
+    QJsonValue result = evaljs(_evaluator,"Tables_getSelectedTableId",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+QJsonObject JSTables::getProperties(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    QJsonValue result = evaljs(_evaluator,"Tables_getProperties",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+void JSTables::setProperties(const QString &itemId, const QString &width)
+{
+    JSArgs args = JSArgs() << itemId << width;
+    evaljs(_evaluator,"Tables_setProperties",args);
+}
+
+void JSTables::setColWidths(const QString &itemId, const QJsonArray &colWidths)
+{
+    JSArgs args = JSArgs() << itemId << colWidths;
+    evaljs(_evaluator,"Tables_setColWidths",args);
+}
+
+QJsonObject JSTables::getGeometry(const QString &itemId)
+{
+    JSArgs args = JSArgs() << itemId;
+    QJsonValue result = evaljs(_evaluator,"Tables_getGeometry",args);
+    return result.isObject() ? result.toObject() : QJsonObject();
+}
+
+// Functions implemented in UndoManager.js
+
+int JSUndoManager::getLength()
+{
+    QJsonValue result = evaljs(_evaluator,"UndoManager_getLength",JSArgs());
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+int JSUndoManager::getIndex()
+{
+    QJsonValue result = evaljs(_evaluator,"UndoManager_getIndex",JSArgs());
+    return result.isDouble() ? result.toDouble() : 0;
+}
+
+void JSUndoManager::setIndex(int index)
+{
+    JSArgs args = JSArgs() << index;
+    evaljs(_evaluator,"UndoManager_setIndex",args);
+}
+
+void JSUndoManager::undo()
+{
+    evaljs(_evaluator,"UndoManager_undo",JSArgs());
+}
+
+void JSUndoManager::redo()
+{
+    evaljs(_evaluator,"UndoManager_redo",JSArgs());
+}
+
+void JSUndoManager::newGroup(const QString &name)
+{
+    JSArgs args = JSArgs() << name;
+    evaljs(_evaluator,"UndoManager_newGroup",args);
+}
+
+QString JSUndoManager::groupType()
+{
+    QJsonValue result = evaljs(_evaluator,"UndoManager_groupType",JSArgs());
+    return result.isString() ? result.toString() : QString::null;
+}
+
+// Functions implemented in Viewport.js
+
+void JSViewport::setViewportWidth(int width)
+{
+    JSArgs args = JSArgs() << width;
+    evaljs(_evaluator,"Viewport_setViewportWidth",args);
+}
+
+void JSViewport::setTextScale(int textScale)
+{
+    JSArgs args = JSArgs() << textScale;
+    evaljs(_evaluator,"Viewport_setTextScale",args);
+}
+
+// All modules
+
+JSInterface::JSInterface(JSEvaluator *evaluator)
+: autoCorrect(evaluator),
+  changeTracking(evaluator),
+  clipboard(evaluator),
+  cursor(evaluator),
+  equations(evaluator),
+  figures(evaluator),
+  formatting(evaluator),
+  input(evaluator),
+  lists(evaluator),
+  main(evaluator),
+  metadata(evaluator),
+  outline(evaluator),
+  preview(evaluator),
+  scan(evaluator),
+  selection(evaluator),
+  styles(evaluator),
+  tables(evaluator),
+  undoManager(evaluator),
+  viewport(evaluator)
+{
+}
diff --git a/consumers/corinthia/src/JSInterface.h b/consumers/corinthia/src/JSInterface.h
new file mode 100644
index 0000000..8cb9e85
--- /dev/null
+++ b/consumers/corinthia/src/JSInterface.h
@@ -0,0 +1,478 @@
+// 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.
+
+#include <QString>
+#include <QRect>
+#include <QJsonObject>
+#include <QJsonArray>
+#include <QTextStream>
+
+/**
+ * \file JSInterface.h
+ *
+ * C++ interface to the JavaScript editor library
+ *
+ * All of the core editing operations for Corinthia are implemented in the Editor library, which is
+ * written in JavaScript. This library can be used either from within a web browser, or, in the case
+ * of the Qt application, from an embedded web view. For this app, we use a QWebView instance which
+ * maintains the in-memory DOM tree of the document, and has injected into it all of the javascript
+ * code that is part of the editor library.
+ *
+ * The source code of the Editor library lives in (repository-root)/Editor/src. During build of the
+ * Qt app, all the javascript files are copied into (build-dir)/share/corinthia/js. If you wish to
+ * make changes to the javascript code, you should modify the files in the former location, as the
+ * latter files will be overwritten on every build.
+ *
+ * The purpose of JSInterface.h and JSInterface.cpp is to provide a C++ wrapper over this. All of
+ * the methods defined in the classes below (with the exception of callbacks) ultimately result in a
+ * call to QWebFrame's evaluateJavaScript() method. See the documentation for JSInterface.cpp for
+ * details.
+ *
+ * The editor library is divided into *modules*, each of which implements a specific aspect of
+ * editing functionality. For example, the Cursor module contains methods for moving the cursor
+ * around the document, and inserting or deleting text at the current cursor position. Similarly,
+ * the Tables module contains methods for inserting, deleting, and modifying tables. A separate C++
+ * class is defined for each module, and an instance of each class is maintained by the "container"
+ * class, JSInterface. When using the code here, you should do so via a JSInterface instance.
+ */
+
+#define JS_MODULE_COMMON(className) \
+Q_DISABLE_COPY(className) \
+public: \
+className(JSEvaluator *evaluator) : JSModule(evaluator) {}
+
+QTextStream& qStdOut();
+QString QRectString(QRect rect);
+
+/**
+ * Callback interface
+ *
+ * While the module classes are for making calls from C++ to JavaScript, the JSCallbacks abstract
+ * class is for responding to requests from JavaScript to invoke C++ code. This is declared here as
+ * an abstract class (that is, with all methods virtual and no implementations provided) to avoid
+ * dependencies between the code in this file and other parts of the application. The
+ * EditorJSCallbacks class in Editor.cpp provides a concrete implementation of this, which is where
+ * the actual callback functions are implemented.
+ *
+ * Callbacks are always invoked *after* the execution of a particular editor library API function,
+ * not during. The reason for this design design in the library was to enable support for web view
+ * classes that did not provide native support for callbacks (as was the case for iOS, at least at
+ * the time the library was originally written).
+ *
+ * The way that callbacks are invoked is that after each editor API call, a query is performed for a
+ * list of pending callback messages. The evaluation logic iterates through these and invokes the
+ * appropriate callback method for each. For this reason, callbacks method are all 'void' - they
+ * never return a value. Callbacks are for notification purposes only - typically telling the
+ * application to update the UI in some manner.
+ */
+class JSCallbacks
+{
+public:
+    virtual ~JSCallbacks() {}
+    virtual void debug(const QString &message) = 0;
+    virtual void addOutlineItem(const QString &itemId, const QString &type, const QString &title) = 0;
+    virtual void updateOutlineItem(const QString &itemId, const QString &title) = 0;
+    virtual void removeOutlineItem(const QString &itemId) = 0;
+    virtual void outlineUpdated() = 0;
+    virtual void setCursor(int x, int y, int width, int height) = 0;
+    virtual void setSelectionHandles(int x1, int y1, int height1, int x2, int y2, int height2) = 0;
+    virtual void setTableSelection(int x, int y, int width, int height) = 0;
+    virtual void setSelectionBounds(int left, int top, int right, int bottom) = 0;
+    virtual void clearSelectionHandlesAndCursor() = 0;
+    virtual void updateAutoCorrect() = 0;
+    virtual void error(const QString &message, const QString &operation) = 0;
+};
+
+/**
+ * The JSEvaluator abstract class provides an evaluate() method which is called (indirectly) by all
+ * of the individual module methods. As with JSCallbacks, it is defined as abstract to avoid a
+ * dependency on the code outside of this file. The EditorJSEvaluator class in Editor.cpp provides a
+ * concrete implementation of this; its evaluate() method simply calls through to the
+ * evaluateJavaScript() method of QWebView.
+ *
+ * JSEvaluator also has a callbacks() method, which must return an instance of JSCallbacks. This
+ * makes JSEvaluator the "central point of contact" between the JavaScript interface and the rest of
+ * the application, in that it provides the necessary access to call *in* to javascript, and to
+ * respond (via callbacks) to calls *out* of javascript. Upon initialisation of a document window,
+ * concrete implementations of both JSCallbacks and JSEvaluator are created, the latter maintaining
+ * a reference to the former. See EditorPrivate::EditorPrivate() for where ths is actually done.
+ */
+class JSEvaluator
+{
+public:
+    virtual ~JSEvaluator() {}
+    virtual QString evaluate(const QString &script) = 0;
+    virtual JSCallbacks *callbacks() = 0;
+};
+
+class JSAutoCorrect;
+class JSChangeTracking;
+class JSClipboard;
+class JSCursor;
+class JSEquations;
+class JSFigures;
+class JSFormatting;
+class JSInput;
+class JSLists;
+class JSMain;
+class JSMetadata;
+class JSOutline;
+class JSPreview;
+class JSScan;
+class JSSelection;
+class JSStyles;
+class JSTables;
+class JSUndoManager;
+class JSViewport;
+class EDScanParagraph;
+
+class JSError
+{
+public:
+    const QString &type() { return _type; }
+    const QString &message() { return _message; }
+    const QString &operation() { return _operation; }
+    const QString &html() { return _html; }
+
+private:
+
+    QString _type;
+    QString _message;
+    QString _operation;
+    QString _html;
+};
+
+class JSModule
+{
+    Q_DISABLE_COPY(JSModule)
+public:
+    JSModule(JSEvaluator *evaluator) : _evaluator(evaluator) {};
+protected:
+    JSEvaluator *_evaluator;
+};
+
+// Functions implemented in AutoCorrect.js
+
+class JSAutoCorrect : public JSModule
+{
+    JS_MODULE_COMMON(JSAutoCorrect)
+    void correctPrecedingWord(int numChars, const QString &replacement, bool confirmed);
+    QJsonObject getCorrection();
+    QJsonObject getCorrectionCoords();
+    void acceptCorrection();
+    void replaceCorrection(const QString &replacement);
+};
+
+// Functions implemented in ChangeTracking.js
+
+class JSChangeTracking : public JSModule
+{
+    JS_MODULE_COMMON(JSChangeTracking)
+    bool showChanges();
+    bool trackChanges();
+    void setShowChanges(bool showChanges);
+    void setTrackChanges(bool trackChanges);
+};
+
+// Functions implemented in Clipboard.js
+
+class JSClipboard : public JSModule
+{
+    JS_MODULE_COMMON(JSClipboard)
+    QJsonObject clipboardCut();
+    QJsonObject clipboardCopy();
+    void pasteHTML(const QString &html);
+    void pasteText(const QString &text);
+};
+
+// Functions implemented in Cursor.js
+
+class JSCursor : public JSModule
+{
+    JS_MODULE_COMMON(JSCursor)
+    QString positionCursor(int x, int y, bool wordBoundary);
+    QRect getCursorPosition();
+    void moveLeft();
+    void moveRight();
+    void moveToStartOfDocument();
+    void moveToEndOfDocument();
+    void insertReference(const QString &itemId);
+    void insertLink(const QString &text, const QString &url);
+    void insertCharacter(unsigned short character, bool allowInvalidPos);
+    void deleteCharacter();
+    void enterPressed();
+    QString getPrecedingWord();
+    QJsonObject getLinkProperties();
+    void setLinkProperties(QJsonObject properties);
+    void setReferenceTarget(const QString &itemId);
+    void insertFootnote(const QString &content);
+    void insertEndnote(const QString &content);
+};
+
+// Functions implemented in Equations.js
+
+class JSEquations : public JSModule
+{
+    JS_MODULE_COMMON(JSEquations)
+    void insertEquation();
+};
+
+// Functions implemented in Figures.js
+
+class JSFigures : public JSModule
+{
+    JS_MODULE_COMMON(JSFigures)
+    void insertFigure(const QString &filename, const QString &width,
+                      bool numbered, const QString &caption);
+    QString getSelectedFigureId();
+    QJsonObject getProperties(const QString &itemId);
+    void setProperties(const QString &itemId, const QString &width, const QString &src);
+    QJsonObject getGeometry(const QString &itemId);
+};
+
+// Functions implemented in Formatting.js
+
+class JSFormatting : public JSModule
+{
+    JS_MODULE_COMMON(JSFormatting)
+    QJsonObject getFormatting();
+    void applyFormattingChanges(const QString &style, QJsonObject properties);
+};
+
+// Functions implemented in Input.js
+
+class JSInput : public JSModule
+{
+    JS_MODULE_COMMON(JSInput)
+    void removePosition(int posId);
+
+    QString textInRange(int startId, int startAdjust, int endId, int endAdjust);
+    void replaceRange(int startId, int endId, const QString &text);
+    QJsonObject selectedTextRange();
+    void setSelectedTextRange(int startId, int endId);
+    QJsonObject markedTextRange();
+    void setMarkedText(const QString &text, int startOffset, int endOffset);
+    void unmarkText();
+    bool forwardSelectionAffinity();
+    void setForwardSelectionAffinity(bool forwardSelectionAffinity);
+    int positionFromPositionOffset(int posId, int offset);
+    int positionFromPositionInDirectionOffset(int posId, const QString &direction, int offset);
+    int comparePositionToPosition(int positionId, int otherId);
+    int offsetFromPositionToPosition(int fromPosition, int toPosition);
+    int positionWithinRangeFarthestInDirection(int startId, int endId, const QString &direction);
+    QJsonObject characterRangeByExtendingPositionInDirection(int positionId, const QString &direction);
+    QJsonObject firstRectForRange(int startId, int endId);
+    QJsonObject caretRectForPosition(int posId);
+    int closestPositionToPoint(int x, int y);
+    int closestPositionToPointWithinRange(int x, int y, int startId, int endId);
+    QJsonObject characterRangeAtPoint(int x, int y);
+    int positionWithinRangeAtCharacterOffset(int startId, int endId, int offset);
+    int characterOffsetOfPositionWithinRange(int positionId, int startId, int endId);
+
+    bool isPositionAtBoundaryGranularityInDirection(int posId, const QString &granularity,
+                                                    const QString &direction);
+    bool isPositionWithinTextUnitInDirection(int posId, const QString &granularity,
+                                             const QString &direction);
+    int positionFromPositionToBoundaryInDirection(int posId, const QString &granularity,
+                                                  const QString &direction);
+    QJsonObject rangeEnclosingPositionWithGranularityInDirection(int posId,
+                                                                 const QString &granularity,
+                                                                 const QString &direction);
+};
+
+// Functions implemented in Lists.js
+
+class JSLists : public JSModule
+{
+    JS_MODULE_COMMON(JSLists)
+    void increaseIndent();
+    void decreaseIndent();
+    void clearList();
+    void setUnorderedList();
+    void setOrderedList();
+};
+
+// Functions implemented in Main.js
+
+class JSMain : public JSModule
+{
+    JS_MODULE_COMMON(JSMain)
+    QString getLanguage();
+    void setLanguage(const QString &language);
+    QString setGenerator(const QString &generator);
+    bool prepareForSave();
+    QString getHTML();
+    bool isEmptyDocument();
+};
+
+// Functions implemented in Metadata.js
+
+class JSMetadata : public JSModule
+{
+    JS_MODULE_COMMON(JSMetadata)
+    QJsonObject getMetadata();
+    void setMetadata(const QJsonObject &metadata);
+};
+
+// Functions implemented in Outline.js
+
+class JSOutline : public JSModule
+{
+    JS_MODULE_COMMON(JSOutline)
+    QJsonObject getOutline();
+    void moveSection(const QString &sectionId, const QString &parentId, const QString &nextId);
+    void deleteItem(const QString &itemId);
+    void goToItem(const QString &itemId);
+    void scheduleUpdateStructure();
+    void setNumbered(const QString &itemId, bool numbered);
+    void setTitle(const QString &itemId, const QString &title);
+    void insertTableOfContents();
+    void insertListOfFigures();
+    void insertListOfTables();
+    void setPrintMode(bool printMode);
+    QJsonObject examinePrintLayout(int pageHeight);
+    bool detectSectionNumbering();
+    QJsonObject findUsedStyles();
+};
+
+// Functions implemented in Preview.js
+
+class JSPreview : public JSModule
+{
+    JS_MODULE_COMMON(JSPreview)
+    void showForStyle(const QString &styleId, const QString &uiName, const QString &title);
+};
+
+// Functions implemented in Scan.js
+
+class JSScan : public JSModule
+{
+    JS_MODULE_COMMON(JSScan)
+    void reset();
+    EDScanParagraph *next();
+    int addMatch(int start, int end);
+    void showMatch(int matchId);
+    void replaceMatch(int matchId, const QString &text);
+    void removeMatch(int matchId);
+    void goToMatch(int matchId);
+};
+
+// Functions implemented in Selection.js
+
+class JSSelection : public JSModule
+{
+    JS_MODULE_COMMON(JSSelection)
+    void update();
+    void selectAll();
+    void selectParagraph();
+    void selectWordAtCursor();
+    QString dragSelectionBegin(int x, int y, bool selectWord);
+    QString dragSelectionUpdate(int x, int y, bool selectWord);
+    QString moveStartLeft();
+    QString moveStartRight();
+    QString moveEndLeft();
+    QString moveEndRight();
+    void setSelectionStartAtCoords(int x, int y);
+    void setSelectionEndAtCoords(int x, int y);
+    void setTableSelectionEdgeAtCoords(const QString &edge, int x, int y);
+    void print();
+};
+
+// Functions implemented in Styles.js
+
+class JSStyles : public JSModule
+{
+    JS_MODULE_COMMON(JSStyles)
+    QString getCSSText();
+    void setCSSText(const QString &cssText, const QJsonObject &rules);
+    QString paragraphClass();
+    void setParagraphClass(const QString &paragraphClass);
+};
+
+// Functions implemented in Tables.js
+
+class JSTables : public JSModule
+{
+    JS_MODULE_COMMON(JSTables)
+    void insertTable(int rows, int cols, const QString &width, bool numbered,
+                     const QString &caption, const QString &className);
+    void addAdjacentRow();
+    void addAdjacentColumn();
+    void removeAdjacentRow();
+    void removeAdjacentColumn();
+    void clearCells();
+    void mergeCells();
+    void splitSelection();
+    QString getSelectedTableId();
+    QJsonObject getProperties(const QString &itemId);
+    void setProperties(const QString &itemId, const QString &width);
+    void setColWidths(const QString &itemId, const QJsonArray &colWidths);
+    QJsonObject getGeometry(const QString &itemId);
+};
+
+// Functions implemented in UndoManager.js
+
+class JSUndoManager : public JSModule
+{
+    JS_MODULE_COMMON(JSUndoManager)
+    int getLength();
+    int getIndex();
+    void setIndex(int index);
+    void undo();
+    void redo();
+    void newGroup(const QString &name);
+    QString groupType();
+};
+
+// Functions implemented in Viewport.js
+
+class JSViewport : public JSModule
+{
+    JS_MODULE_COMMON(JSViewport)
+    void setViewportWidth(int width);
+    void setTextScale(int textScale);
+};
+
+// All modules
+
+class JSInterface
+{
+    Q_DISABLE_COPY(JSInterface)
+public:
+    JSInterface(JSEvaluator *evaluator);
+    JSAutoCorrect autoCorrect;
+    JSChangeTracking changeTracking;
+    JSClipboard clipboard;
+    JSCursor cursor;
+    JSEquations equations;
+    JSFigures figures;
+    JSFormatting formatting;
+    JSInput input;
+    JSLists lists;
+    JSMain main;
+    JSMetadata metadata;
+    JSOutline outline;
+    JSPreview preview;
+    JSScan scan;
+    JSSelection selection;
+    JSStyles styles;
+    JSTables tables;
+    JSUndoManager undoManager;
+    JSViewport viewport;
+};
+
+void processCallbacks(JSEvaluator *evaluator);
diff --git a/consumers/corinthia/src/MainWindow.cpp b/consumers/corinthia/src/MainWindow.cpp
new file mode 100644
index 0000000..cb2a280
--- /dev/null
+++ b/consumers/corinthia/src/MainWindow.cpp
@@ -0,0 +1,101 @@
+// 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.
+
+#include "MainWindow.h"
+#include <QWebView.h>
+#include <QVBoxLayout>
+#include <QPushButton>
+#include <QCoreApplication>
+#include "Editor.h"
+#include "JSInterface.h"
+#include "Toolbar.h"
+
+MainWindow::MainWindow(QApplication *app) : QWidget(0)
+{
+    _app = app;
+    _toolbar = new Toolbar(this);
+    _editor = new Editor(this);
+    QVBoxLayout *vlayout = new QVBoxLayout();
+    this->setLayout(vlayout);
+    vlayout->addWidget(_toolbar);
+    vlayout->addWidget(_editor);
+    vlayout->setSpacing(0);
+    vlayout->setContentsMargins(4,4,4,4);
+
+    QObject::connect(_toolbar->tableButton(),SIGNAL(clicked()),this,SLOT(insertTable()));
+    QObject::connect(_toolbar->linkButton(),SIGNAL(clicked()),this,SLOT(insertLink()));
+    QObject::connect(_toolbar->characterButton(),SIGNAL(clicked()),this,SLOT(insertCharacter()));
+    QObject::connect(_toolbar->backspaceButton(),SIGNAL(clicked()),this,SLOT(backspace()));
+    QObject::connect(_toolbar->leftButton(),SIGNAL(clicked()),this,SLOT(moveLeft()));
+    QObject::connect(_toolbar->rightButton(),SIGNAL(clicked()),this,SLOT(moveRight()));
+    QObject::connect(_toolbar->undoButton(),SIGNAL(clicked()),this,SLOT(undo()));
+    QObject::connect(_toolbar->redoButton(),SIGNAL(clicked()),this,SLOT(redo()));
+
+    QString appPath = QCoreApplication::applicationDirPath();
+    QString docPath = appPath + "/../share/corinthia/sample.html";
+    QUrl url = QUrl::fromLocalFile(docPath);
+    qStdOut() << "sample document url = " << url.toString() << endl;
+    _editor->webView()->load(url);
+}
+
+MainWindow::~MainWindow()
+{
+    delete _toolbar;
+    delete _editor;
+}
+
+void MainWindow::insertTable()
+{
+    _editor->js()->tables.insertTable(4,3,"50%",true,"Table caption",QString::null);
+}
+
+void MainWindow::insertLink()
+{
+    _editor->js()->cursor.insertLink("Corinthia website","http://corinthia.incubator.apache.org");
+}
+
+void MainWindow::insertCharacter()
+{
+    _editor->js()->cursor.insertCharacter('X',true);
+}
+
+void MainWindow::backspace()
+{
+    _editor->js()->cursor.deleteCharacter();
+}
+
+void MainWindow::moveLeft()
+{
+    _editor->js()->cursor.moveLeft();
+}
+
+void MainWindow::moveRight()
+{
+    _editor->js()->cursor.moveRight();
+}
+
+void MainWindow::undo()
+{
+    _editor->js()->undoManager.undo();
+}
+
+void MainWindow::redo()
+{
+    _editor->js()->undoManager.redo();
+}
+
+//#include <MainWindow.moc>
diff --git a/consumers/corinthia/src/MainWindow.h b/consumers/corinthia/src/MainWindow.h
new file mode 100644
index 0000000..0a2693b
--- /dev/null
+++ b/consumers/corinthia/src/MainWindow.h
@@ -0,0 +1,42 @@
+// 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.
+
+#include <QWidget>
+
+class Toolbar;
+class Editor;
+
+class MainWindow : public QWidget
+{
+    Q_OBJECT
+public:
+    MainWindow(QApplication *app);
+    ~MainWindow();
+    public slots:
+    void insertTable();
+    void insertLink();
+    void insertCharacter();
+    void backspace();
+    void moveLeft();
+    void moveRight();
+    void undo();
+    void redo();
+private:
+    QApplication *_app;
+    Toolbar *_toolbar;
+    Editor *_editor;
+};
diff --git a/consumers/corinthia/src/Toolbar.cpp b/consumers/corinthia/src/Toolbar.cpp
new file mode 100644
index 0000000..4a6faf6
--- /dev/null
+++ b/consumers/corinthia/src/Toolbar.cpp
@@ -0,0 +1,50 @@
+// 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.
+
+#include "Toolbar.h"
+#include <QPushButton>
+#include <QHBoxLayout>
+
+Toolbar::Toolbar(QWidget *parent) : QWidget(parent)
+{
+    _tableButton = new QPushButton("Insert table",0);
+    _linkButton = new QPushButton("Insert link",0);
+    _characterButton = new QPushButton("Insert character",0);
+    _backspaceButton = new QPushButton("Backspace",0);
+    _leftButton = new QPushButton("Move left",0);
+    _rightButton = new QPushButton("Move right",0);
+    _undoButton = new QPushButton("Undo",0);
+    _redoButton = new QPushButton("Redo",0);
+
+    _layout = new QHBoxLayout();
+    this->setLayout(_layout);
+
+    _layout->addWidget(_tableButton);
+    _layout->addWidget(_linkButton);
+    _layout->addWidget(_characterButton);
+    _layout->addWidget(_backspaceButton);
+    _layout->addWidget(_leftButton);
+    _layout->addWidget(_rightButton);
+    _layout->addWidget(_undoButton);
+    _layout->addWidget(_redoButton);
+    _layout->setSpacing(4);
+    _layout->setContentsMargins(0,0,0,0);
+}
+
+Toolbar::~Toolbar()
+{
+}
diff --git a/consumers/corinthia/src/Toolbar.h b/consumers/corinthia/src/Toolbar.h
new file mode 100644
index 0000000..207eafc
--- /dev/null
+++ b/consumers/corinthia/src/Toolbar.h
@@ -0,0 +1,49 @@
+// 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.
+
+#include <QWidget>
+
+class QPushButton;
+class QHBoxLayout;
+
+class Toolbar : public QWidget
+{
+    Q_OBJECT
+public:
+    Toolbar(QWidget *parent = 0);
+    ~Toolbar();
+
+    QPushButton *tableButton() { return _tableButton; }
+    QPushButton *linkButton() { return _linkButton; }
+    QPushButton *characterButton() { return _characterButton; }
+    QPushButton *backspaceButton() { return _backspaceButton; }
+    QPushButton *leftButton() { return _leftButton; }
+    QPushButton *rightButton() { return _rightButton; }
+    QPushButton *undoButton() { return _undoButton; }
+    QPushButton *redoButton() { return _redoButton; }
+
+private:
+    QPushButton *_tableButton;
+    QPushButton *_linkButton;
+    QPushButton *_characterButton;
+    QPushButton *_backspaceButton;
+    QPushButton *_leftButton;
+    QPushButton *_rightButton;
+    QPushButton *_undoButton;
+    QPushButton *_redoButton;
+    QHBoxLayout *_layout;
+};
diff --git a/consumers/corinthia/src/main.cpp b/consumers/corinthia/src/main.cpp
new file mode 100644
index 0000000..f17f506
--- /dev/null
+++ b/consumers/corinthia/src/main.cpp
@@ -0,0 +1,27 @@
+// 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.
+
+#include <QApplication>
+#include "MainWindow.h"
+
+int main(int argc, char *argv[])
+{
+    QApplication *app = new QApplication(argc, argv);
+    MainWindow *window = new MainWindow(app);
+    window->show();
+    return app->exec();
+}
diff --git a/consumers/dfconvert/src/CMakeLists.txt b/consumers/dfconvert/src/CMakeLists.txt
index 8b18959..595fe21 100644
--- a/consumers/dfconvert/src/CMakeLists.txt
+++ b/consumers/dfconvert/src/CMakeLists.txt
@@ -16,7 +16,6 @@
 ###
 ## global definitions
 ###
-cmake_minimum_required(VERSION 2.8)
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 
diff --git a/consumers/dfconvert/src/main.c b/consumers/dfconvert/src/main.c
index b2bacb3..7295691 100644
--- a/consumers/dfconvert/src/main.c
+++ b/consumers/dfconvert/src/main.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include <DocFormats/DocFormats.h>
@@ -42,6 +45,8 @@
            "\n"
            "    Create a new Word document from a HTML file. The Word document must\n"
            "    not already exist.\n"
+           "\n"
+           "dfconvert does not yet convert odf or latex files.\n"
            "\n");
 }
 
@@ -65,7 +70,7 @@
         return 0;
     }
 
-    fprintf(stderr,"%s\n",DFErrorMessage(&error));
+    fprintf(stderr,"Error: %s\n",DFErrorMessage(&error));
     DFErrorRelease(error);
     return 1;
 }
diff --git a/consumers/dftest/src/CMakeLists.txt b/consumers/dftest/src/CMakeLists.txt
index 4a2a58c..738e9b1 100644
--- a/consumers/dftest/src/CMakeLists.txt
+++ b/consumers/dftest/src/CMakeLists.txt
@@ -16,7 +16,6 @@
 ###
 ## global definitions
 ###
-cmake_minimum_required(VERSION 2.8)
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 
diff --git a/consumers/dftest/src/main.c b/consumers/dftest/src/main.c
index b3fd6b0..2621b89 100644
--- a/consumers/dftest/src/main.c
+++ b/consumers/dftest/src/main.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "DFUnitTest.h"
@@ -90,7 +93,7 @@
     for (int i = 0; lines[i]; i++) {
         if (!DFStringIsWhitespace(lines[i]) && strncmp(lines[i],"//",2)) {
             if (command == NULL)
-                command = strdup(lines[i]);
+                command = xstrdup(lines[i]);
             count++;
         }
     }
@@ -112,7 +115,7 @@
     const char *closebr = strrchr(command,')');
 
     if ((openbr == NULL) && (closebr == NULL)) {
-        DFArray *array = DFArrayNew((DFCopyFunction)strdup,free);
+        DFArray *array = DFArrayNew((DFCopyFunction)xstrdup,free);
         DFArrayAppend(array,(void *)command);
         const char **result = DFStringArrayFlatten(array);
         DFArrayRelease(array);
@@ -137,7 +140,7 @@
     char *arguments = DFSubstring(command,openpos+1,closepos);
 
     const char **components = DFStringSplit(arguments,",",0);
-    DFArray *array = DFArrayNew((DFCopyFunction)strdup,free);
+    DFArray *array = DFArrayNew((DFCopyFunction)xstrdup,free);
     DFArrayAppend(array,name);
     for (int i = 0; components[i]; i++) {
         char *trimmed = DFStringTrimWhitespace(components[i]);
@@ -275,7 +278,7 @@
 
 void runTests(int argc, const char **argv, int diff)
 {
-    DFArray *tests = DFArrayNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    DFArray *tests = DFArrayNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
     for (int i = 0; i < argc; i++) {
         const char *path = argv[i];
         if (!DFFileExists(path)) {
diff --git a/consumers/dfutil/src/CMakeLists.txt b/consumers/dfutil/src/CMakeLists.txt
index 6847569..0ed75db 100644
--- a/consumers/dfutil/src/CMakeLists.txt
+++ b/consumers/dfutil/src/CMakeLists.txt
@@ -16,7 +16,6 @@
 ###
 ## global definitions
 ###
-cmake_minimum_required(VERSION 2.8)
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 
diff --git a/consumers/dfutil/src/Commands.c b/consumers/dfutil/src/Commands.c
index 530acd2..7ec5827 100644
--- a/consumers/dfutil/src/Commands.c
+++ b/consumers/dfutil/src/Commands.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "Commands.h"
@@ -53,7 +56,7 @@
     DFBuffer *buffer = readData(filename,error);
     if (buffer == NULL)
         return NULL;
-    char *result = strdup(buffer->data);
+    char *result = xstrdup(buffer->data);
     DFBufferRelease(buffer);
     return result;
 }
@@ -123,6 +126,34 @@
     return ok;
 }
 
+static int prettyPrintODFFile(const char *filename, DFError **error)
+{
+    int ok = 0;
+    char *odf = NULL;
+    DFStorage *storage = NULL;
+
+    storage = DFStorageOpenZip(filename,error);
+
+    if (storage == NULL) {
+        DFErrorFormat(error,"%s: %s",filename,DFErrorMessage(error));
+        goto end;
+    }
+    /*
+    odf = ODF_toPlain(storage,NULL);
+    printf("%s",odt);
+    */
+    printf("ODF file support has not been implemented yet.\n");
+    ok = 1;
+
+end:
+    free(odf);
+    DFStorageRelease(storage);
+    return ok;
+
+}
+
+
+
 int prettyPrintFile(const char *filename, DFError **error)
 {
     int ok;
@@ -133,6 +164,8 @@
         ok = prettyPrintXMLFile(filename,1,error);
     else if (DFStringEqualsCI(extension,"docx"))
         ok = prettyPrintWordFile(filename,error);
+    else if (DFStringEqualsCI(extension,"odt"))
+        ok = prettyPrintODFFile(filename,error);
     else {
         DFErrorFormat(error,"Unknown file type");
         ok = 0;
@@ -174,7 +207,7 @@
     if (inStr == NULL)
         return 0;
 
-    char *inPath = fromStdin ? strdup(".") : DFPathDirName(inFilename);
+    char *inPath = fromStdin ? xstrdup(".") : DFPathDirName(inFilename);
     int ok = fromPlain2(inStr,inPath,outFilename,error);
     free(inPath);
     free(inStr);
@@ -296,7 +329,7 @@
             return 0;
         }
         free(value);
-        value = strdup(DFHashTableLookup(package->items,name));
+        value = xstrdup(DFHashTableLookup(package->items,name));
         if (value == NULL) {
             DFErrorFormat(error,"%s: Item %s not found",filename,itemPath);
             TextPackageRelease(package);
@@ -341,7 +374,7 @@
 void parseContent(const char *content)
 {
     DFArray *parts = CSSParseContent(content);
-    printf("parts.count = %lu\n",DFArrayCount(parts));
+    printf("parts.count = %zu\n",DFArrayCount(parts));
     for (size_t i = 0; i < DFArrayCount(parts); i++) {
         ContentPart *part = DFArrayItemAt(parts,i);
         char *quotedValue = DFQuote(part->value);
diff --git a/consumers/dfutil/src/Commands.h b/consumers/dfutil/src/Commands.h
index 69b8912..93114a3 100644
--- a/consumers/dfutil/src/Commands.h
+++ b/consumers/dfutil/src/Commands.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef dfutil_Commands_h
 #define dfutil_Commands_h
diff --git a/consumers/dfutil/src/FunctionTests.h b/consumers/dfutil/src/FunctionTests.h
index f5a3238..5f2ee23 100644
--- a/consumers/dfutil/src/FunctionTests.h
+++ b/consumers/dfutil/src/FunctionTests.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef dfutil_FunctionTests_h
 #define dfutil_FunctionTests_h
diff --git a/consumers/dfutil/src/FunctionTests.m b/consumers/dfutil/src/FunctionTests.m
index f458cc3..037ac45 100644
--- a/consumers/dfutil/src/FunctionTests.m
+++ b/consumers/dfutil/src/FunctionTests.m
@@ -1,18 +1,22 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #import <Foundation/Foundation.h>
+#include "DFPlatform.h"
 #include "FunctionTests.h"
 #include "DFString.h"
 #include "DFFilesystem.h"
diff --git a/consumers/dfutil/src/StringTests.h b/consumers/dfutil/src/StringTests.h
index d864035..7971147 100644
--- a/consumers/dfutil/src/StringTests.h
+++ b/consumers/dfutil/src/StringTests.h
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #ifndef dfutil_StringTests_h
 #define dfutil_StringTests_h
diff --git a/consumers/dfutil/src/StringTests.m b/consumers/dfutil/src/StringTests.m
index 7e16c51..aca2524 100644
--- a/consumers/dfutil/src/StringTests.m
+++ b/consumers/dfutil/src/StringTests.m
@@ -1,18 +1,22 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #import <Foundation/Foundation.h>
+#include "DFPlatform.h"
 #include "StringTests.h"
 #include "DFString.h"
 
diff --git a/consumers/dfutil/src/dfutil-Prefix.pch b/consumers/dfutil/src/dfutil-Prefix.pch
deleted file mode 100644
index a0d2737..0000000
--- a/consumers/dfutil/src/dfutil-Prefix.pch
+++ /dev/null
@@ -1,7 +0,0 @@
-//
-// Prefix header for all source files of the 'dom' target in the 'dom' project
-//
-
-#ifdef __OBJC__
-    #import <Foundation/Foundation.h>
-#endif
diff --git a/consumers/dfutil/src/main.c b/consumers/dfutil/src/main.c
index fed55ab..c3b1ba5 100644
--- a/consumers/dfutil/src/main.c
+++ b/consumers/dfutil/src/main.c
@@ -1,16 +1,19 @@
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 #include "DFPlatform.h"
 #include "Commands.h"
diff --git a/consumers/dfwebserver/.gitignore b/consumers/dfwebserver/.gitignore
new file mode 100644
index 0000000..3cd6f04
--- /dev/null
+++ b/consumers/dfwebserver/.gitignore
@@ -0,0 +1,2 @@
+pool
+uploads
\ No newline at end of file
diff --git a/consumers/dfwebserver/assets/input.docx b/consumers/dfwebserver/assets/input.docx
new file mode 100644
index 0000000..9de8bc3
--- /dev/null
+++ b/consumers/dfwebserver/assets/input.docx
Binary files differ
diff --git a/consumers/dfwebserver/examples/node/server/.gitignore b/consumers/dfwebserver/examples/node/server/.gitignore
new file mode 100644
index 0000000..b512c09
--- /dev/null
+++ b/consumers/dfwebserver/examples/node/server/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/consumers/dfwebserver/examples/node/server/package.json b/consumers/dfwebserver/examples/node/server/package.json
new file mode 100644
index 0000000..215730a
--- /dev/null
+++ b/consumers/dfwebserver/examples/node/server/package.json
@@ -0,0 +1,17 @@
+{
+  "name": "server_example",
+  "version": "1.0.0",
+  "description": "",
+  "main": "server.js",
+  "dependencies": {
+    "express": "^4.12.3",
+    "multer": "^0.1.8"
+  },
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1",
+    "start": "node server.js"
+  },
+  "author": "",
+  "license": "apache2"
+}
diff --git a/consumers/dfwebserver/examples/node/server/server.js b/consumers/dfwebserver/examples/node/server/server.js
new file mode 100644
index 0000000..ec79dfc
--- /dev/null
+++ b/consumers/dfwebserver/examples/node/server/server.js
@@ -0,0 +1,105 @@
+var express = require('express'),
+    multer  = require('multer')
+
+var path = require('path');
+var fs = require('fs');
+
+var docformats = require('../../../node/src/docformats');
+docformats.options.binaryPath = path.resolve('../../../../../build/bin');
+
+
+var app = express();
+
+var dfwebserver = path.resolve(__dirname, '../../..');
+var web = path.resolve(__dirname, '../../../../web');
+
+app.get('/upload', function(req, res){
+  res.send('<html><head></head><body>\
+               <form method="POST" enctype="multipart/form-data">\
+                <input type="file" name="filefield"><br />\
+                <input type="submit">\
+              </form>\
+            </body></html>');
+});
+
+var multerOptions = { 
+    dest: path.resolve(dfwebserver, 'uploads/'),
+    rename: function (fieldname, filename) {
+        return filename;
+    }
+};
+
+app.post('/upload',[ multer(multerOptions), function(req, res){
+    console.log(req.body) // form fields
+    console.log(req.files) // form files
+    //res.json(req.files).status(204).end()
+    
+  res.send('<html><head></head><body>\
+               <a href="/get/' + req.files.filefield.name + '/">Navigate to this link to run dfconvert GET in the server\
+                </a>\
+            </body></html>');
+}]);
+
+
+function getInput(id) {
+    return path.resolve(dfwebserver, 'uploads', id);
+}
+
+function getOutput(id) {
+    var folder = path.resolve(dfwebserver, 'pool', id)
+    var parsed = path.parse(folder);
+    
+    return path.resolve(folder, parsed.name + '.html');
+}
+
+function getDynamicResource(id, resource) {
+    var folder = path.resolve(dfwebserver, 'pool', id)
+
+    return path.resolve(folder, resource);
+}
+
+function getStaticResource(resource) {
+    return path.resolve(web, 'client', resource);
+}
+
+function sendFile(res, filename) {
+    if (fs.existsSync(filename)) {
+        res.sendFile(filename);
+    } else {
+        res.status(404).end(); // Not Found
+    }
+}
+
+
+app.get('/get/:id', function(req, res){
+    var input = getInput(req.params.id);
+    var abstract = getOutput(req.params.id);
+    
+    try {
+        // This is required because DocFormat API throw an error
+        // when abstract is present in the filesystem
+        fs.unlinkSync(abstract); 
+    } catch (ex) {
+        // do nothing
+    }
+    docformats.get(input, abstract);
+    sendFile(res, abstract);
+});
+
+app.get('/get/:id/*', function(req, res){
+    var staticResource = getStaticResource(req.params[0]);
+    var dynamicResource = getDynamicResource(req.params.id, req.params[0]);
+    
+    if (fs.existsSync(staticResource)) {
+        res.sendFile(staticResource);
+    } else {
+        sendFile(res, dynamicResource);
+    }
+});
+
+
+
+app.listen(process.env.PORT || 8080);
+
+
+
diff --git a/consumers/dfwebserver/examples/node/simple.js b/consumers/dfwebserver/examples/node/simple.js
new file mode 100644
index 0000000..4b2b0cf
--- /dev/null
+++ b/consumers/dfwebserver/examples/node/simple.js
@@ -0,0 +1,10 @@
+var docformats = require('../../node/src/docformats');
+var path = require("path");
+
+docformats.options.binaryPath = path.resolve('../../../../build/bin');
+
+var input = path.resolve('../../assets/input.docx');
+var abstract = path.resolve('../../pool/input.docx/input.html');
+
+var status = docformats.get(input, abstract);
+console.log(status);
\ No newline at end of file
diff --git a/consumers/dfwebserver/node/.gitignore b/consumers/dfwebserver/node/.gitignore
new file mode 100644
index 0000000..2f6141d
--- /dev/null
+++ b/consumers/dfwebserver/node/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+npm-debug.log
+.DS_Store
\ No newline at end of file
diff --git a/consumers/dfwebserver/node/.npmignore b/consumers/dfwebserver/node/.npmignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/consumers/dfwebserver/node/.npmignore
diff --git a/consumers/dfwebserver/node/LICENSE b/consumers/dfwebserver/node/LICENSE
new file mode 100644
index 0000000..90705e0
--- /dev/null
+++ b/consumers/dfwebserver/node/LICENSE
@@ -0,0 +1,16 @@
+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.
\ No newline at end of file
diff --git a/consumers/dfwebserver/node/package.json b/consumers/dfwebserver/node/package.json
new file mode 100644
index 0000000..5a3746b
--- /dev/null
+++ b/consumers/dfwebserver/node/package.json
@@ -0,0 +1,16 @@
+{
+  "name": "docformats",
+  "version": "0.0.2",
+  "description": "Wrapper for DocFormats API",
+  "main": "src/docformats.js",
+  "dependencies": {
+    "mkdirp": "^0.5.0"
+  },
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "franzdecopenhague",
+  "license": "apache2"
+}
+
diff --git a/consumers/dfwebserver/node/src/docformats.js b/consumers/dfwebserver/node/src/docformats.js
new file mode 100644
index 0000000..f94a751
--- /dev/null
+++ b/consumers/dfwebserver/node/src/docformats.js
@@ -0,0 +1,27 @@
+'use strict';
+
+var path = require('path');
+var exec = require('child_process').execFileSync;
+var mkdirp = require("mkdirp").sync;
+
+var df = exports;
+
+df.options = {binaryPath : null};
+
+df.get = function (input, abstract) {
+    try {
+        var cmd = null;
+        if (df.options.binaryPath === undefined || df.options.binaryPath === null) {
+            cmd = 'dfconvert';
+        } else {
+            cmd = path.join(df.options.binaryPath, 'dfconvert');
+        }
+        console.log(cmd + " get " + input + " " + abstract + "");
+        mkdirp(path.dirname(abstract));
+        exec(cmd, ['get', input, abstract]);
+    } catch (ex) {
+        console.log(ex);
+        return false;
+    }
+    return true;
+};
\ No newline at end of file
diff --git a/consumers/dfwebserver/pool/sample.docx/sample.html b/consumers/dfwebserver/pool/sample.docx/sample.html
new file mode 100644
index 0000000..c7a584a
--- /dev/null
+++ b/consumers/dfwebserver/pool/sample.docx/sample.html
@@ -0,0 +1,1130 @@
+<!DOCTYPE html>
+
+<html lang="en-AU">
+<head>
+  <meta charset="utf-8">
+  <meta name="generator" content="UX Write 2.0.2 (build 4b4faea); iOS 7.1">
+
+  <title></title>
+  <style>
+blockquote {
+    font-style: italic;
+  }
+
+  body {
+    counter-reset: h1 h2 h3 h4 h5 h6 figure table;
+    font-family: Palatino;
+    xmargin: 10%;
+    text-align: justify;
+  }
+
+  caption {
+    caption-side: bottom;
+    counter-increment: table;
+  }
+
+  caption.Unnumbered {
+    counter-increment: table 0;
+  }
+
+  caption.Unnumbered::before, figcaption.Unnumbered::before {
+    content: "";
+  }
+
+  caption::before {
+    content: "Table " counter(table) ": ";
+  }
+
+  figcaption {
+    counter-increment: figure;
+  }
+
+  figcaption.Unnumbered {
+    counter-increment: figure 0;
+  }
+
+  figcaption::before {
+    content: "Figure " counter(figure) ": ";
+  }
+
+  figure {
+    margin-bottom: 12pt;
+    margin-left: auto;
+    margin-right: auto;
+    margin-top: 12pt;
+    text-align: center;
+  }
+
+  h1 {
+    counter-increment: h1;
+    counter-reset: h2 h3 h4 h5 h6;
+  }
+
+  h1.Unnumbered, h2.Unnumbered, h3.Unnumbered, h4.Unnumbered, h5.Unnumbered, h6.Unnumbered {
+  }
+
+  h1::before {
+    content: counter(h1) " ";
+  }
+
+  h2 {
+    color: #585958;
+    counter-increment: h2;
+    counter-reset: h3 h4 h5 h6;
+  }
+
+  h2::before {
+    content: counter(h1) "." counter(h2) " ";
+  }
+
+  h3 {
+    counter-increment: h3;
+    counter-reset: h4 h5 h6;
+  }
+
+  h3::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) " ";
+  }
+
+  h4 {
+    counter-increment: h4;
+    counter-reset: h5 h6;
+  }
+
+  h4::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) " ";
+  }
+
+  h5 {
+    counter-increment: h5;
+    counter-reset: h6;
+  }
+
+  h5::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) " ";
+  }
+
+  h6 {
+    counter-increment: h6;
+  }
+
+  h6::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) " ";
+  }
+
+  nav.listoffigures::before {
+    content: "List of Figures";
+    display: block;
+    font-size: 2em;
+    font-weight: bold;
+    margin-bottom: .67em;
+    margin-top: .67em;
+  }
+
+  nav.listoftables::before {
+    content: "List of Tables";
+    display: block;
+    font-size: 2em;
+    font-weight: bold;
+    margin-bottom: .67em;
+    margin-top: .67em;
+  }
+
+  nav.tableofcontents::before {
+    content: "Contents";
+    display: block;
+    font-size: 2em;
+    font-weight: bold;
+    margin-bottom: .67em;
+    margin-top: .67em;
+  }
+
+  p {
+    line-height: 166%;
+  }
+
+  p.abstract {
+    font-style: italic;
+    margin-left: 20%;
+    margin-right: 20%;
+  }
+
+  p.author {
+    font-size: 18pt;
+    text-align: center;
+  }
+
+  p.NoSpacing {
+    margin: 0%;
+  }
+
+  p.SpecialNote {
+    color: red;
+    font-weight: bold;
+    text-align: center;
+  }
+
+  p.Tip {
+    background-color: #eeeeee;
+    border: hidden;
+    border-radius: 10px;
+    margin-left: 5%;
+    margin-right: 5%;
+    padding: 10pt;
+  }
+
+  p.Title {
+    font-size: 36pt;
+    font-weight: bold;
+    margin-bottom: 24pt;
+    text-align: center;
+    text-decoration: underline;
+  }
+
+  p.toc1 {
+    margin-bottom: 6pt;
+    margin-left: 0pt;
+    margin-top: 12pt;
+  }
+
+  p.toc2 {
+    margin-bottom: 6pt;
+    margin-left: 24pt;
+    margin-top: 6pt;
+  }
+
+  p.toc3 {
+    margin-bottom: 6pt;
+    margin-left: 48pt;
+    margin-top: 6pt;
+  }
+
+  table {
+    border-collapse: collapse;
+    margin-left: auto;
+    margin-right: auto;
+  }
+
+  td > :first-child, th > :first-child {
+    margin-top: 0;
+  }
+
+  td > :last-child, th > :last-child {
+    margin-bottom: 0;
+  }
+
+  td, th {
+    border: 1px solid black;
+  }
+  </style>
+</head>
+
+<body>
+
+  <h1 id="item9">Introduction</h1>
+
+  <p>UX Write is designed for long-form, professional writing tasks such as
+  reports, research papers, theses, and books. With an emphasis on technical
+  and academic writing, it provides tools to work with the <i>content</i> and
+  <i>structure</i> of your document separately from its <i>presentation</i>.
+  The latter is controlled by <i>styles</i>, such as headings, normal
+  paragraphs, and the document title.</p>
+
+  <h2 id="item19">What you see is what you mean</h2>
+
+  <p>The design philosophy of UX Write is “what you see is what you mean”, or
+  WYSIWYM. By separating content from presentation, and making the logical
+  structure of documents explicit, it is possible for the layout and rendering
+  of text to adapt to the output medium. This means your documents look just as
+  good on a 30“ desktop monitor as they do on a 7” tablet or the printed
+  page.</p>
+
+  <p>The structure of your document — such as the hierarchy of section headings
+  — also enables other useful features. A table of contents is generated
+  automatically, without you having to manually update text or page numbers.
+  Cross-references can be added and kept up-to-date as section numbers change.
+  The outline view, accessible from the toolbar, displays all the sections,
+  figures, and tables in your document, allowing you to navigate around
+  easily.</p>
+
+  <p>A contrasting approach is “what you see is what you get”, or WYSIWYG,
+  supported by programs like Microsoft Word and Pages. This attempts to
+  replicate the precise layout of a printed page on screen during editing,
+  regardless of whether you're using a desktop computer or a mobile phone.
+  While useful for some purposes, we believe it's the wrong approach for a
+  mobile word processor. UX Write is unapologetically WYSIWYM, and is optimised
+  for readability and ease-of-use across both iPhone and iPad.</p>
+
+  <p class="Tip">If you've got this document open for editing, take a moment
+  now to explore the document outline (third toolbar button from right). Try
+  adjusting the text size in the “Look &amp; feel” section of the settings menu
+  (second from right) to suit your reading preferences. Rotate your screen and
+  watch as the text reflows.</p>
+
+  <h2 id="item17">File formats</h2>
+
+  <p>The native file format of UX Write is HTML — the language of the web. You
+  can view HTML documents on any device or operating system out there, and
+  publish online without any need for file conversion. If you open a Microsoft
+  Word document, it is temporarily converted to HTML for editing, and then
+  saved back again afterwards. Any parts of the document that could not be
+  converted, such as embedded spreadsheets, are preserved in the original Word
+  document.</p>
+
+  <h1 id="item8">Basic features</h1>
+
+  <h2 id="item11">Accessing your Documents</h2>
+
+  <p>You can store your documents on your device only — under
+  “My iPad” or “My iPhone” — or sync them with a cloud service such as Dropbox.
+  In the former case, you can transfer files to your computer using <a href=
+  "http://support.apple.com/kb/HT4094">iTunes file sharing</a>, and in the
+  latter case you can either access your files through the respective service's
+  website, or by installing the service's software on your computer. Box,
+  Dropbox, Google Drive, and Microsoft OneDrive all have clients available for
+  Windows and Mac which you can install for free.</p>
+
+  <p>File synchronisation happens automatically. Whenever a
+  document is saved, it is uploaded&nbsp; in the background, while you continue
+  working. If you have your computer set up for syncing, you will usually see
+  these changes appear within a few seconds. Within UX Write, you can check for
+  updates to existing documents using the refresh button.</p>
+
+  <p>If you're working offline, you can still add and change documents in any
+  of the Box, Dropbox, Google Drive, OneDrive or WebDAV locations you have set
+  up. When you have an Internet connection available again, just launch UX
+  Write, and it will attempt to upload the documents. To move, copy, or delete
+  documents, simply tap the “Edit” button in the file browser.</p>
+
+  <p class="Tip"><b>Tip:</b> We recommend creating and storing all your
+  documents on Dropbox, because it keeps backup copies of every version
+  uploaded for 30 days. You can view and recover old versions of your document
+  if the need arises — see Section <a href="#item10">4.1</a>.</p>
+
+  <h2 id="item4">Editing</h2>
+
+  <p>Text editing works in much the same way as in any other iOS app, but with
+  a few enhancements:</p>
+
+  <ul>
+    <li>
+      <p>An extra row of keys above the keyboard provides access to common
+      punctuation symbols</p>
+    </li>
+
+    <li>
+      <p>The two leftmost keys let you move the cursor or select text by
+      holding them down to bring up a virtual trackpad. Swipe with one finger
+      to move slowly, and two fingers to move faster.</p>
+    </li>
+
+    <li>
+      <p>The formatting key, when held down, replaces the other top-row keys
+      with keys for basic formatting options like bold, italic, and lists</p>
+    </li>
+
+    <li>
+      <p>The autocorrect key allows you to confirm or revert the latest
+      autocorrect replacement (see Section <a href="#item2">2.5</a> for more
+      details)</p>
+    </li>
+
+    <li>
+      <p>You can triple-tap anywhere in the text to select the whole
+      paragraph</p>
+    </li>
+  </ul>
+
+  <p>Note: The keyboard extensions are only available on the iPad.</p>
+
+  <p>UX Write also includes full support for external bluetooth keyboards, and
+  supports all of the standard keyboard shortcuts:</p>
+
+  <table style="width: 100%;" id="item7">
+    <caption>
+      Keyboard shortcuts
+    </caption>
+
+    <colgroup>
+      <col width="50%">
+      <col width="50%">
+    </colgroup>
+
+    <tbody>
+      <tr>
+        <td>
+          <p>Cmd-B</p>
+        </td>
+
+        <td>
+          <p>Bold</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-I</p>
+        </td>
+
+        <td>
+          <p>Italic</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-U</p>
+        </td>
+
+        <td>
+          <p>Underline</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-X</p>
+        </td>
+
+        <td>
+          <p>Cut</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-C</p>
+        </td>
+
+        <td>
+          <p>Copy</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-V</p>
+        </td>
+
+        <td>
+          <p>Paste</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-A</p>
+        </td>
+
+        <td>
+          <p>Select all</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Option-Left/Right</p>
+        </td>
+
+        <td>
+          <p>Move back or forward one word</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Option-Up/Down</p>
+        </td>
+
+        <td>
+          <p>Move up or down one paragraph</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-Left/Right</p>
+        </td>
+
+        <td>
+          <p>Move to start or end of line</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-Up/Down</p>
+        </td>
+
+        <td>
+          <p>Move to start of end of document</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Shift-Arrow key (+ Cmd or Option)</p>
+        </td>
+
+        <td>
+          <p>Any of the above, but for selection</p>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+
+  <h2 id="item5">Styles</h2>
+
+  <p>All formatting in UX Write, with the exception of
+  bold,&nbsp;italic, underline and lists, is controlled using <i>styles</i> —
+  such as headings and normal paragraphs. A style serves two purposes:</p>
+
+  <ol>
+    <li>
+      <p>It determines the <i>formatting</i> of the text, such
+      as the font, colour, and paragraph alignment. When a style is modified,
+      all text associated with that style automatically adopts the new
+      formatting, making it easy to ensure consistent presentation throughout
+      your document.</p>
+    </li>
+
+    <li>
+      <p>It indicates the <i>purpose</i> of a piece of text,
+      such as a heading or title. UX Write uses this information for various
+      purposes, such as building a table of contents, displaying the outline
+      view, and determining the possible targets for cross-references.</p>
+    </li>
+  </ol>
+
+  <p>UX Write Basic Edition provides a plain set of built-in styles for
+  headings, block quotes, a document title, and normal text. UX Write
+  Professional Edition allows you to modify the appearance of these built-in
+  styles, as well as create your own; see Section&nbsp;<a href=
+  "#item29">3.1</a> for details.</p>
+
+  <h2 id="item6">Auto correct</h2>
+
+  <p>Automatic correction of typing mistakes can sometimes lead to unexpected
+  results, since no piece of software can accurately guess what you meant to
+  type in every case. When UX Write makes a correction, it highlights it in
+  green, and gives you the opportunity to confirm whether or not it has made
+  the right replacement.</p>
+
+  <p>Tapping on a highlighted word brings up a menu that allows you to accept
+  the correction, revert to the original, or bring up a list of more
+  suggestions, with the option to add the word to the custom dictionary. Any
+  substitutions you explicitly accept are remembered by UX Write, and will
+  occur automatically the next time you make the same typing mistake. You can
+  access the custom dictionary and list of automatic substitutions via the
+  settings menu.</p>
+
+  <h2 id="item2">Outline Navigation</h2>
+
+  <p>You can use the outline view — the third toolbar button
+  from the right — to view the structure of your document and quickly jump
+  between sections. This is particularly useful for large documents, where
+  scrolling would be a hassle.</p>
+
+  <p>The outline view is based on the headings, figures, and
+  tables in your document. For headings to be included, you must mark them as
+  such using the formatting menu. Tables and figures are always included. As
+  you modify your document by adding, removing, or changing content, the
+  outline is automatically kept up-to-date. UX Write Professional Edition also
+  allows you to edit the outline — see Section <a href="#item30">3.4</a> for
+  details.</p>
+
+  <p>In landscape mode on the iPad, you can “pin” the outline to
+  the left of your screen, and it will be displayed alongside your document. To
+  pin or unpin it, use the button at the top of the outline. To hide the
+  outline when it is pinned, press the 'X' button.</p>
+
+  <p>The outline view corresponds directly to what in the table
+  of contents, list of figures, and list of tables, if you have added any of
+  these to your document. See Section&nbsp;<a href="#item32">3.9</a> for
+  details.</p>
+
+  <h1 id="item27">Professional features</h1>
+
+  <p>This section describes features that are only available in
+  UX Write Professional Edition. You can upgrade to this by either purchasing
+  it outright, or by subscribing on a monthly basis. Go to the settings menu
+  and select “View upgrade options” to see details.</p>
+
+  <h2 id="item29">Styles</h2>
+
+  <p>Styles, introduced in Section&nbsp;<a href=
+  "#item5">2.3</a>, define both the formatting and purpose of text in your
+  document. Heading styles, for instance, denote the document outline, and are
+  used for constructing the table of contents. Each style can have different
+  formatting properties, such as fonts, colours, margins, paragraph alignment,
+  borders, and more.</p>
+
+  <p>Using styles enables you to achieve consistent formatting
+  throughout your entire document. Instead of manually changing formatting on a
+  case-by-case basis — as many other word processors encourage you to do — you
+  adjust a style once and it applies to all text in the document associated
+  with the style. This is useful for ensuring your document complies with
+  requirements from your organisation or publisher.</p>
+
+  <p>UX Write provides a number of built-in styles, based on
+  those present in HTML. There are six levels of headings, in addition
+  to&nbsp;normal paragraphs and block quotes. You can change the way any of
+  these are formatted, and also add your own custom styles for specific
+  purposes. For example, this document contains a “Tip” style, which appears as
+  a light-grey box with rounded corners, and left and right margins that place
+  it in the center of the page.</p>
+
+  <p>To manage styles, go to the formatting menu, and select
+  “Edit Styles”. This will bring up the style manager, with a list of styles on
+  the left, and formatting properties on either the top or right of the screen
+  (depending on your screen orientation).</p>
+
+  <p>To edit an existing style, simply select it in the list, and change any of
+  the formatting properties. You will see a preview displayed below the
+  controls that shows an example piece of text as it would be displayed in the
+  document.</p>
+
+  <p>To add a new style, scroll down to the bottom of the list and tap next to
+  the green '+' button. Type in your style name and press enter. You can now
+  set up the formatting for this style, and subsequently select it from the
+  formatting menu in the editor.</p>
+
+  <p>Direct formatting is still available if you want it, via
+  the item near the bottom of the formatting menu. This gives you the same
+  properties as are available in the style editor, but the changes only apply
+  to the current selection.</p>
+
+  <p>Styles you create in UX Write are compatible with Word, and
+  you can also edit and use the styles in Word itself.</p>
+
+  <p class="Tip"><b>Tip:</b> If you want to re-use your styles with multiple
+  documents, you can set up a template for creating new documents. See Section
+  <a href="#item15">3.13</a> for details.</p>
+
+  <h2 id="item39">Formatting</h2>
+
+  <p>There are two ways to adjust formatting:</p>
+
+  <ul>
+    <li>
+      <p><b>Styles.</b> You can select these from the formatting
+      menu; they apply at the paragraph level. Generally, you should use styles
+      to control formatting, as this provides structural information about the
+      document (in the case of headings), and allows you to easily change
+      formatting throughout the whole document for any given style.</p>
+    </li>
+
+    <li>
+      <p><b>Direct formatting.</b> You can also select this from
+      the formatting menu; this is intended for “one-off” cases where you wish
+      to format a particular piece of text without defining a style, such as
+      highlighting something important. You have access to all the same
+      formatting options as you do for styles. Direct formatting corresponds to
+      what you would see in the toolbar of Microsoft Word; we've deliberately
+      de-emphasised it in the user interface to encourage the use of
+      styles.</p>
+    </li>
+  </ul>
+
+  <p>All of the formatting properties directly correspond to
+  those of CSS (Cascading Style Sheets), the web standard used in conjunction
+  with HTML. In most cases, the CSS formatting properties UX Write supports can
+  also be translated directly to those of Microsoft Word; the main exception is
+  that Word has a slightly different way of handling paragraph borders and
+  margins.</p>
+
+  <p>Formatting properties are divided into two categories:
+  <i>text</i> and <i>paragraph</i>. Text properties, in the case of direct
+  formatting, can be applied to only a portion of a paragraph. The rest apply
+  to the paragraph as a whole.</p>
+
+  <h2 id="item26">Document structure</h2>
+
+  <p>Most formal documents like reports and books are divided
+  into multiple levels of <b>sections</b>, with <b>cross-references</b> between
+  them, and a <b>table of contents</b> at the front. Styles are key to
+  achieving this, because the program needs to be told which pieces of text are
+  headings — it can't simply guess that “18 point bold” means a second-level
+  heading. By using styles to mark all your headings, you can take advantage of
+  the following features:</p>
+
+  <ul>
+    <li>
+      <p>Table of contents (Insert menu)</p>
+    </li>
+
+    <li>
+      <p>Cross-references (Insert menu)</p>
+    </li>
+
+    <li>
+      <p>Automatic numbering</p>
+    </li>
+
+    <li>
+      <p>Outline editor (Outline button on toolbar)</p>
+    </li>
+  </ul>
+
+  <p>Whenever a section number changes as a result of changes
+  earlier in the document, its number is automatically updated, as are those of
+  all references that point to it, and the table of contents. The same is true
+  of figures and tables. When you print or generate a PDF, page numbers are
+  automatically calculated for you and included in the table of contents.</p>
+
+  <h2 id="item30">Outline editing</h2>
+
+  <p>You can rearrange and delete sections in the outline by
+  pressing the “Edit button”. To change the order of sections, tap and drag the
+  section name to your desired position. To delete an item, just press the red
+  button on the left, and confirm by pressing the “Delete” button that appears.
+  All changes you make in the outline editor are immediately reflected in the
+  document, including updates to numbering.</p>
+
+  <h2 id="item35">Find and replace</h2>
+
+  <p>On iPad, a search bar is visible at the top of the screen,
+  and you can just type in your search term and hit enter. Tap the down arrow
+  to view options, including replacement text. On iPhone, the search bar and
+  options are accessible via the settings menu.</p>
+
+  <p>By default, searching will look for the exact text you have
+  entered, with case sensitivity determined by whether you have selected that
+  option. Alternatively, you can search and replace text using <i>regular
+  expressions</i>, which allow you to enter patterns that can match multiple
+  snippets of text. Regular expression support is mainly intended for advanced
+  users, such as programmers, who are already familiar with the concept. If you
+  would like to learn more, we recommend the tutorial at at&nbsp;<a href=
+  "http://regexone.com">regexone.com</a>.</p>
+
+  <h2 id="item36">Spell checking</h2>
+
+  <p>The spell checking option will search through your document
+  and highlight any instances of words it finds which are not in the system or
+  custom dictionaries.</p>
+
+  <p>The language&nbsp;used is determined by the following three
+  settings, in order:</p>
+
+  <ul>
+    <li>
+      <p>Language for the current document (Settings &gt; This
+      Document &gt; Language)</p>
+    </li>
+
+    <li>
+      <p>Default language for UX Write (Settings &gt;
+      Application &gt; Language)</p>
+    </li>
+
+    <li>
+      <p>System language (set in the Settings app of your iPad
+      or iPhone)</p>
+    </li>
+  </ul>
+
+  <p>There is currently no support for handling multiple
+  languages in a single document. The set of languages available for spell
+  checking is determined by the built-in dictionaries provided by the operating
+  system, which as of 7.1 are:</p>
+
+  <ul>
+    <li>
+      <p class="NoSpacing">Danish</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Dutch</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">English (Australia)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">English (Canada)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">English (United Kingdom)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">English (United States)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">French</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">German</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Italian</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Portuguese (Brazil)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Portuguese (Portugal)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Russian</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Spanish</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Swedish</p>
+    </li>
+  </ul>
+
+  <h2 id="item37">Word count</h2>
+
+  <p>You can view the word count for your document from the
+  settings menu. This also includes the total number of characters and
+  paragraphs.</p>
+
+  <h2 id="item31">Automatic numbering</h2>
+
+  <p>UX Write can assign numbers to all headings, figures, and
+  tables automatically. For headings, you can turn this on using the “Heading
+  numbering” option in the settings menu. For figures and tables, you can set
+  this on an individual basis either at insertion time, or by tapping on the
+  item and selecting “Figure” or “Table” in the popup menu.</p>
+
+  <p>Numbering is updated automatically as the document changes.
+  If you add or remove a heading, change it's nesting level (e.g.
+  from&nbsp;Heading 2 to Heading 1), or move sections around using the outline
+  editor, the numbers will be updated to reflect the changes. The same is also
+  true for figures and tables.</p>
+
+  <p>All cross-references, plus the table of contents, list of
+  figures, and list of tables (if present) are also kept up to date whenever
+  the numbers change. This ensures that you never have out-of-date references
+  and you don't have to remember to manually update other parts of the
+  document.&nbsp;</p>
+
+  <h2 id="item32">Table of contents</h2>
+
+  <p>While it's possible to manually create a table of contents
+  in any word processor, doing so is tedious, particularly when keeping all the
+  section titles and page numbers up to date. In UX Write, inserting a table of
+  contents causes it to be constructed automatically based on the headings,
+  just like the outline view described in Section&nbsp;<a href=
+  "#item30">3.4</a>. And like automatic numbering and the outline view, every
+  time you add or remove a section, or change its title, the table of contents
+  automatically updates to reflect the change.</p>
+
+  <p>Page numbers are <i>not</i> displayed in the table of
+  contents during editing or when saving as a HTML file, as neither has any
+  concept of distinct pages. When you print or export to PDF, the correct page
+  numbers will be filled in for you. There's no need to do this manually.</p>
+
+  <p>You can also insert a list of figures or list of tables,
+  which work similarly to the table of contents. The text shown in these comes
+  from the captions, with the numbers shown in the same way as section numbers.
+  As with the table of contents, these are always kept in sync with the rest of
+  document.</p>
+
+  <p>If your document is in HTML format, the table of contents,
+  list of figures, and list of tables will appear as links that can be clicked
+  to jump to the appropriate section when viewed in a web browser.</p>
+
+  <h2 id="item1">Cross-references</h2>
+
+  <p>You can insert a cross-reference to any section heading,
+  figure, or table in your document. When you select this option from the
+  insert menu, you'll see a document outline (the same as in the outline view),
+  and can select a target of the cross-reference.</p>
+
+  <p>References appear as hyperlinks in the document. When you
+  tap on one, you'll have the option to either go to the target of the
+  reference, or change it to point to a different section, figure, or
+  table.</p>
+
+  <p>If your reference is to a numbered heading, figure, or
+  table, the number will be updated whenever that of its target changes. If the
+  target is not numbered, the reference will contain the text instead, and will
+  also update whenever the text changes.</p>
+
+  <h2 id="item3">Footnotes and endnotes</h2>
+
+  <p>Because UX Write uses a continuous layout for editing, in
+  which the document is not divided into separate pages, footnotes are
+  displayed inline with the text<span class="footnote">A footnote looks like
+  this</span>. For consistency, and to avoid the need to jump back and forth
+  between the content and the end of the document, endnotes are handled in the
+  same way<span class="endnote">An endnote looks like this</span>.</p>
+
+  <p>HTML does not have any explicit support for either
+  footnotes or endnotes, in the sense that there is no &lt;footnote&gt; element
+  that can clearly indicate its purpose. UX Write uses &lt;span&gt; elements
+  with a class of “footnote” or “endnote” to represent these.</p>
+
+  <p>Microsoft Word documents <i>do</i> have explicit support
+  for both, so when editing a .docx file, UX Write will save them in the
+  appropriate format. When you open the document in Word, you'll see footnotes
+  at the bottom of the page, and endnotes at the end of the document.</p>
+
+  <p>To have footnotes and endnotes appear in their correct
+  positions in a print or PDF output, you must use the LaTeX typesetting option
+  (see Section&nbsp;<a href="#item23">3.12</a>). WebKit does not have the
+  capabilities to support pagination features.</p>
+
+  <h2 id="item23">Printing and PDF export</h2>
+
+  <p>Two different typesetting systems are supported for
+  producing print and PDF output. You can choose between these using the
+  “Typesetting” option under the settings menu:</p>
+
+  <ul>
+    <li>
+      <p><b>WebKit</b> (recommended). Safari's layout engine,
+      optimised for on-screen rendering of HTML content.</p>
+
+      <p>This is the layout engine used for displaying your
+      documents during editing, and the PDF files it generates match exactly
+      the formatting you see on screen; though line breaks will be different
+      for the printed page.</p>
+    </li>
+
+    <li>
+      <p><b>LaTeX</b> (new). The de-facto standard in many
+      scientific disciplines, optimised for high-quality typography and
+      paginated output.</p>
+
+      <p>Support for LaTeX is new in 2.0. Currently, only
+      limited formatting options are supported, and English is the only
+      supported language. We'll be improving this throughout the 2.x release
+      cycle, with support for other languages and many other features, such as
+      equations, bibliographies, and headers/footers.</p>
+    </li>
+  </ul>
+
+  <p>Of these two, only LaTeX is capable of correctly
+  typesetting footnotes and endnotes, as well as other pagination-dependent
+  features we'll be adding in the future. If you print or export to PDF using
+  WebKit, footnotes and endnotes will appear inline with the text, as they do
+  during editing.</p>
+
+  <h2 id="item15">Creating Templates</h2>
+
+  <p>Often you'll want to create a series of documents which all have a
+  consistent look and feel, based on styles that you have set up, as described
+  in Section <a href="#item29">3.1</a>. While UX Write does not have a “proper”
+  template feature (yet), you can get the same effect by creating a normal
+  document with your desired settings, and treating that as a starting point
+  for new documents.</p>
+
+  <p>To create a template:</p>
+
+  <ol>
+    <li>
+      <p>Create a new document, calling it “My template” (or whatever you
+      like)</p>
+    </li>
+
+    <li>
+      <p>Open the document and use the style manager to change the default
+      fonts, colours, and other formatting properties that you want</p>
+    </li>
+
+    <li>
+      <p>Create any custom styles that you will use regularly — e.g. “Title” or
+      “Abstract”</p>
+    </li>
+  </ol>
+
+  <p>To create a new document based on a template:</p>
+
+  <ol>
+    <li>
+      <p>Tap and hold on the template document in the file manager</p>
+    </li>
+
+    <li>
+      <p>Select “Duplicate”</p>
+    </li>
+
+    <li>
+      <p>Type in the name for your new document</p>
+    </li>
+
+    <li>
+      <p>Open the new document and start writing</p>
+    </li>
+  </ol>
+
+  <p>We'll be adding a more sophisticated mechanism for browsing and previewing
+  template files, along with a few nice samples, in a future update.</p>
+
+  <h1 id="item13">Common Tasks</h1>
+
+  <h2 id="item10">Dropbox Versioning</h2>
+
+  <p>One of the best features of Dropbox is that it automatically keeps old
+  versions of every file that's uploaded to it. It's always been possible to
+  log into the Dropbox website and access these old versions via their web
+  interface, but now you can do it directly from within UX Write itself.</p>
+
+  <p>If you ever need to recover an older version of a document, simply tap and
+  hold on it in the file browser, and select “Versions” in the popup menu. You
+  can then browse through all the versions that Dropbox has kept, and restore
+  the one you want. UX Write autosaves every three minutes, so if you're
+  connected to the Internet while you're working, you'll have regular snapshots
+  of your documents.<b></b></p>
+
+  <h2 id="item12">Converting from HTML to docx</h2>
+
+  <p>If you've upgraded from a previous version of UX Write and wish to convert
+  your HTML documents to .docx so they can be used with Microsoft Word, you can
+  do so as follows:</p>
+
+  <ul>
+    <li>
+      <p>Tap and hold on the document in the file browser</p>
+    </li>
+
+    <li>
+      <p>Select <b>Convert to</b> <b>docx</b></p>
+    </li>
+  </ul>
+
+  <p>Note that due to differences between the two file formats, there may be
+  some loss of formatting during the transition — for example, the rounded
+  borders used in the “Tip” style in this document can't be represented in
+  docx. For this reason, the original HTML file will be kept as a backup.</p>
+
+  <h1 id="item16">Troubleshooting</h1>
+
+  <h2 id="item18">Reporting Bugs</h2>
+
+  <p>If you encounter a crash in UX Write, you will be asked if you would like
+  to submit a bug report. This report includes a crash log indicating exactly
+  where in the program the problem occurred, as well as a redacted copy of your
+  document in which all text and images have been removed. An email window will
+  appear where you can add comments about what happened, and the bug report
+  will be sent to us when you hit “Send”. You can CC yourself a copy for
+  reference if you like.</p>
+
+  <p><b>If we can't reproduce it, we can't fix it.</b> Many people send in bug
+  reports containing just the crash log. Often, we can to determine from this
+  what went wrong, but this isn't always the case. To increase the chances of
+  us being able to fix the problem, try to provide a detailed description of
+  what you were doing right before the crash occurred.</p>
+
+  <p>The best bug reports provide a clear set of steps that explain how to
+  reproduce the problem. During beta testing of 2.0, one particularly helpful
+  person even used iPad screen recording software to make a video demonstrating
+  how to trigger a bug, edited the video in iMovie, and added an audio track
+  with narration to explain what was going on. You certainly don't have to go
+  to this much effort, but a few simple instructions in your email which
+  explain how to reliably reproduce a problem will help a lot.</p>
+
+  <p>If you encounter any other issues that do not involve a crash, such as
+  formatting inconsistencies or strange user interface behaviour, just select
+  the <b>Submit bug report</b>&nbsp;option from the settings menu and send us a
+  note. Remember, the more information, the better.</p>
+
+  <p>The app store does not provide developers with any way to directly respond
+  to bug reports included in reviews. You can say whatever you want, but
+  <b>please also let us know about your problem</b> in case we need to ask you
+  for more information in order to fix it.</p>
+
+  <h2 id="item14">Purchase and Subscription</h2>
+
+  <p>Every time you install something from the app store, iOS
+  includes a <i>receipt file</i> which is accessible to the app. This file
+  includes information about the version number of the app that you originally
+  downloaded, as well as any in-app payments you have made. UX Write looks at
+  this file to determine whether or not to enable the features in the
+  professional edition.</p>
+
+  <p>If you buy a new iPad or iPhone and install UX Write on it
+  via iTunes, this receipt file might not be present. If you have purchased or
+  subscribed to the app, it's necessary for UX Write to request a copy of the
+  receipt file from the app store so it can verify your upgrade status. You can
+  do this either from the intro screen shown at first launch, or by selecting
+  “Reactivate existing upgrade” from the settings menu.</p>
+
+  <p>If you originally purchased UX Write prior to the release
+  of version 2.0 (when it was a paid-only app), you should automatically have
+  access to the professional edition. The way UX Write determines this is by
+  looking at the receipt file and checking what the version number of the app
+  was at the time of your purchase. So if you see the app running as basic
+  edition, select “Reactivate existing upgrade” from the settings menu.</p>
+
+  <p>If you have any problems with upgrades or payments,
+  <a href="http://www.uxproductivity.com/support">please contact us</a>.</p>
+
+  <h2 id="item20">The Field Update Problem</h2>
+
+  <p>If you open a .docx file in Word after editing it in UX Write, you'll see
+  the following message:</p>
+
+  <blockquote>
+    “This document contains fields that may refer to other files. Do you want
+    to update the fields in this document?”
+  </blockquote>
+
+  <p>When you see this message, just click <b>Yes</b> (or press the <b>Y</b>
+  key).</p>
+
+  <p>Sadly, this is a symptom of a design flaw in Word, and is something only
+  Microsoft can fix. Unlike UX Write, Word does not keep the table of contents,
+  cross references, or figure/table numbers (all collectively known as
+  <b>Fields</b>) up to date automatically. Instead, it forces you to manually
+  tell it when it to update the fields after you have made changes to your
+  document.</p>
+
+  <p>Despite the fact that UX Write never actually produces fields that refer
+  to other files, this message is still displayed in every version of Word that
+  we have tested with, including Word 2013. The only way we could prevent such
+  a dialog from appearing is to store a setting in the document that tells Word
+  that there is no need to update the fields — but this would simply leave you
+  with an invalid table of contents and incorrect cross-references. While we've
+  done our best to ensure that UX Write provides the best user experience
+  within the app itself, we're not able to fix Word.</p>
+
+  <h2 id="item22">Opening .doc files</h2>
+
+  <p>Microsoft Word has used a number of different file formats over the years,
+  and UX Write only supports the most recent version, .docx, which is a modern,
+  XML-based, well-documented open standard. The older .doc format is a
+  proprietary and very complex binary file format that would take a minimum of
+  six months to support. We've decided that time is better spent on other
+  useful features instead.</p>
+
+  <p>If you have a .doc file that you wish to edit in UX Write, you can convert
+  it to .docx by opening it in any recent version of Word (2007 and later), and
+  using “Save as” to convert it to docx. Doing so will maintain all of the
+  content and formatting, and provide exactly the same experience when working
+  with the document in Word itself. You will then have your document in a much
+  more portable format, and be able to edit it in Word, UX Write, and other
+  word processors such as LibreOffice.</p>
+
+  <h1 id="item28">More information</h1>
+
+  <p>If you have a question that isn't answered here, check out
+  our <a href="http://www.uxproductivity.com/support">support website</a> for
+  more info. We also maintain a <a href=
+  "http://blog.uxproductivity.com">blog</a> discussing the development of the
+  app and new features that are in the works. Many of our posts discuss various
+  questions people have had about UX Write and may provide you with a deeper
+  understanding of why certain aspects of the app are the way they are.</p>
+
+  <p>We value any feedback you have about the app, and you can
+  send it to us any time via the option on the settings menu. We receive a
+  <i>lot</i> of email, and can't guarantee to respond individually or add every
+  requested feature, but we certainly take into account your feedback when
+  deciding on priorities for future updates.</p>
+</body>
+</html>
diff --git a/consumers/dfwebserver/python/input.docx b/consumers/dfwebserver/python/input.docx
new file mode 100644
index 0000000..9de8bc3
--- /dev/null
+++ b/consumers/dfwebserver/python/input.docx
Binary files differ
diff --git a/consumers/dfwebserver/python/makefile b/consumers/dfwebserver/python/makefile
new file mode 100644
index 0000000..b3546c3
--- /dev/null
+++ b/consumers/dfwebserver/python/makefile
@@ -0,0 +1,48 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+#build
+#  make
+
+#install
+#  sudo python setup.py install
+
+#unistall 
+#  sudo python setup.py install --record files.txt
+#  cat files.txt | sudo xargs rm -rf      
+
+#develoment build
+#  make clean dev
+#  python test.py
+
+LDFLAGS ?= ""
+CFLAGS ?= ""
+
+.PHONY: default build_ext clean
+
+default: build_ext
+
+dev:
+	CFLAGS=$(CFLAGS) LDFLAGS=$(LDFLAGS) python setup.py build_ext --inplace --debug
+
+build_ext:
+	CFLAGS=$(CFLAGS) LDFLAGS=$(LDFLAGS) python setup.py build_ext --debug
+
+clean:
+	- rm -rf build
+	- rm -rf consumers
+	- rm -f output*.html
+	- rm -f output*.docx
+	- rm -f dummy*.docx
+	- find ./ -name '*.so' -delete
diff --git a/consumers/dfwebserver/python/other.html b/consumers/dfwebserver/python/other.html
new file mode 100644
index 0000000..14778ef
--- /dev/null
+++ b/consumers/dfwebserver/python/other.html
@@ -0,0 +1 @@
+<begin>text</begin>
\ No newline at end of file
diff --git a/consumers/dfwebserver/python/setup.py b/consumers/dfwebserver/python/setup.py
new file mode 100644
index 0000000..8675b22
--- /dev/null
+++ b/consumers/dfwebserver/python/setup.py
@@ -0,0 +1,64 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from distutils.core import setup, Extension
+
+# define the extension module
+dfutil_module = Extension('dfutil', 
+    sources=['src/dfutil.c', '../../consumers/dfutil/src/Commands.c'],
+    libraries = ['DocFormats', 'xml2'],
+    extra_compile_args = ['-std=c99'],
+    library_dirs = ['../../build/lib'],
+    include_dirs = [
+        '../../DocFormats/api/headers', 
+        '../../DocFormats/core/src/common',
+        '../../DocFormats/core/src/css', 
+        '../../DocFormats/core/src/html', 
+        '../../DocFormats/core/src/lib', 
+        '../../DocFormats/core/src/names', 
+        '../../DocFormats/core/src/xml', 
+        '../../DocFormats/core/tests/common', 
+        '../../DocFormats/core/tests/html',
+        '../../DocFormats/filters/latex/src',
+        '../../DocFormats/filters/ooxml/src/common', 
+        '../../DocFormats/filters/ooxml/src/word', 
+        '../../DocFormats/filters/ooxml/tests/word',
+        '../../DocFormats/headers',
+    ]
+)
+
+dfconvert_module = Extension('dfconvert', 
+    sources=['src/dfconvert.c'],
+    libraries = ['DocFormats', 'xml2', 'SDL2', 'SDL_image'],
+    extra_compile_args = ['-std=c99'],
+    library_dirs = ['../../build/lib'],
+    include_dirs = [
+        '../../DocFormats/api/headers', 
+        '../../DocFormats/core/src/common',
+        '../../DocFormats/core/src/css', 
+        '../../DocFormats/core/src/html', 
+        '../../DocFormats/core/src/lib', 
+        '../../DocFormats/core/src/names', 
+        '../../DocFormats/core/src/xml', 
+        '../../DocFormats/core/tests/common', 
+        '../../DocFormats/core/tests/html',
+        '../../DocFormats/filters/latex/src',
+        '../../DocFormats/filters/ooxml/src/common', 
+        '../../DocFormats/filters/ooxml/src/word', 
+        '../../DocFormats/filters/ooxml/tests/word',
+        '../../DocFormats/headers',
+    ]
+)
+
+# run the setup
+setup(ext_modules=[dfutil_module, dfconvert_module])  
diff --git a/consumers/dfwebserver/python/src/dfconvert.c b/consumers/dfwebserver/python/src/dfconvert.c
new file mode 100644
index 0000000..b284222
--- /dev/null
+++ b/consumers/dfwebserver/python/src/dfconvert.c
@@ -0,0 +1,108 @@
+// 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.
+
+#include <Python.h>
+
+typedef struct DFError DFError;
+void DFErrorRelease(DFError *error);
+const char *DFErrorMessage(DFError **error);
+
+// Abstraction level 1
+
+int DFGetFile(const char *concrete, const char *abstract, DFError **error);
+int DFPutFile(const char *concrete, const char *abstract, DFError **error);
+int DFCreateFile(const char *concrete, const char *abstract, DFError **error);
+              
+
+static PyObject* get_func(PyObject* self, PyObject* args)
+{
+    DFError *error = NULL;
+    
+    char * concrete = NULL;
+    char * abstract = NULL;
+    
+    if (!PyArg_ParseTuple(args, "ss", &concrete, &abstract)) {
+        return NULL;
+    }    
+    
+    if (DFGetFile(concrete, abstract, &error)) {
+        Py_RETURN_TRUE;
+    }
+
+    fprintf(stderr,"%s\n",DFErrorMessage(&error));
+    DFErrorRelease(error);
+    Py_RETURN_FALSE;
+}
+
+static PyObject* put_func(PyObject* self, PyObject* args)
+{
+    DFError *error = NULL;
+    
+    char * concrete = NULL;
+    char * abstract = NULL;
+    
+    if (!PyArg_ParseTuple(args, "ss", &concrete, &abstract)) {
+        return NULL;
+    }    
+    
+    if (DFPutFile(concrete, abstract, &error)) {
+        Py_RETURN_TRUE;
+    }
+
+    fprintf(stderr,"%s\n",DFErrorMessage(&error));
+    DFErrorRelease(error);
+    Py_RETURN_FALSE;
+}
+
+static PyObject* create_func(PyObject* self, PyObject* args)
+{
+    DFError *error = NULL;
+    
+    char * concrete = NULL;
+    char * abstract = NULL;
+    
+    if (!PyArg_ParseTuple(args, "ss", &concrete, &abstract)) {
+        return NULL;
+    }    
+    
+    if (DFCreateFile(concrete, abstract, &error)) {
+        Py_RETURN_TRUE;
+    }
+
+    fprintf(stderr,"%s\n",DFErrorMessage(&error));
+    DFErrorRelease(error);
+    Py_RETURN_FALSE;
+}
+
+
+/*  define functions in module */
+static PyMethodDef dfconvertMethods[] =
+{
+     {"get", get_func, METH_VARARGS, "Create a new HTML file from input document"},
+     {"put", put_func, METH_VARARGS, "Update an existing Word document based on a modified HTML file."},
+     {"create", create_func, METH_VARARGS, "Create a new Word document from a HTML file. The Word document must not already exist."},
+     {NULL, NULL, 0, NULL}
+};
+
+
+/* module initialization */
+PyMODINIT_FUNC
+
+initdfconvert(void)
+{
+     (void) Py_InitModule("dfconvert", dfconvertMethods);
+}
diff --git a/consumers/dfwebserver/python/src/dfutil.c b/consumers/dfwebserver/python/src/dfutil.c
new file mode 100644
index 0000000..9e7b689
--- /dev/null
+++ b/consumers/dfwebserver/python/src/dfutil.c
@@ -0,0 +1,64 @@
+// 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.
+
+#include <Python.h>
+
+typedef struct DFError DFError;
+void DFErrorRelease(DFError *error);
+const char *DFErrorMessage(DFError **error);
+
+int normalizeFile(const char *filename, DFError **error);
+
+static PyObject* normalize_func(PyObject* self, PyObject* args)
+{
+    DFError *dferr = NULL;
+    
+    char * filename = NULL;
+    
+    if (!PyArg_ParseTuple(args, "s", &filename)) {
+        return NULL;
+        /* if the above function returns -1, an appropriate Python exception will
+        * have been set, and the function simply returns NULL
+        */
+    }
+    
+    if (filename!=NULL) {
+        if (1 == normalizeFile(filename, &dferr)) {
+            Py_RETURN_TRUE;
+        }
+        fprintf(stderr,"%s\n",DFErrorMessage(&dferr));
+        DFErrorRelease(dferr);
+    }
+    
+    Py_RETURN_FALSE;
+}
+
+
+/*  define functions in module */
+static PyMethodDef dfutilMethods[] =
+{
+     {"normalize", normalize_func, METH_VARARGS, "evaluate the sine"},
+     {NULL, NULL, 0, NULL}
+};
+
+/* module initialization */
+PyMODINIT_FUNC
+
+initdfutil(void)
+{
+     (void) Py_InitModule("dfutil", dfutilMethods);
+}
diff --git a/consumers/dfwebserver/python/test.py b/consumers/dfwebserver/python/test.py
new file mode 100644
index 0000000..213ee2b
--- /dev/null
+++ b/consumers/dfwebserver/python/test.py
@@ -0,0 +1,42 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# To test:
+#
+# make clean dev
+# python test.py
+
+import unittest
+
+import dfutil
+import dfconvert
+import shutil
+
+
+class MyTest(unittest.TestCase):
+    def test(self):
+        
+        self.assertTrue(dfutil.normalize("other.html"))
+
+        self.assertTrue(dfconvert.get("input.docx", "output.html"))
+        
+        shutil.copyfile("input.docx", "dummy.docx");
+        
+        self.assertTrue(dfconvert.put("dummy.docx", "output.html"))
+        
+        self.assertTrue(dfconvert.create("output.docx", "output.html"))
+        
+        
+if __name__ == '__main__':
+    unittest.main()        
+
diff --git a/consumers/dfwebserver/python/testSubprocess.py b/consumers/dfwebserver/python/testSubprocess.py
new file mode 100644
index 0000000..e3bcfa6
--- /dev/null
+++ b/consumers/dfwebserver/python/testSubprocess.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import threading
+import time
+
+import dfconvert
+
+exitFlag = 0
+
+class dfconvertThread (threading.Thread):
+    def __init__(self, threadID, name, input, abstract):
+        threading.Thread.__init__(self)
+        self.threadID = threadID
+        self.name = name
+        self.input = input
+        self.abstract = abstract
+    def run(self):
+        print "Starting " + self.name
+        if exitFlag:
+            thread.exit()
+        status = dfconvert.get(self.input, self.abstract);
+        print "%s: %s status:%s" % (self.name, time.ctime(time.time()), status)
+        print "Exiting " + self.name
+
+# Create new threads
+thread1 = dfconvertThread(1, "Thread-1", "input.docx", "output1.html")
+thread2 = dfconvertThread(2, "Thread-2", "input.docx", "output2.html")
+thread3 = dfconvertThread(3, "Thread-3", "input.docx", "output3.html")
+thread4 = dfconvertThread(4, "Thread-4", "input.docx", "output4.html")
+thread5 = dfconvertThread(5, "Thread-5", "input.docx", "output5.html")
+
+# Start new Threads
+thread1.start()
+thread2.start()
+thread3.start()
+thread4.start()
+thread5.start()
+
+print "Exiting Main Thread"
\ No newline at end of file
diff --git a/consumers/dfwebserver/src/dfconvert.c b/consumers/dfwebserver/src/dfconvert.c
new file mode 100644
index 0000000..99698fc
--- /dev/null
+++ b/consumers/dfwebserver/src/dfconvert.c
@@ -0,0 +1,91 @@
+#include <Python.h>
+
+typedef struct DFError DFError;
+void DFErrorRelease(DFError *error);
+const char *DFErrorMessage(DFError **error);
+
+// Abstraction level 1
+
+int DFGetFile(const char *concrete, const char *abstract, DFError **error);
+int DFPutFile(const char *concrete, const char *abstract, DFError **error);
+int DFCreateFile(const char *concrete, const char *abstract, DFError **error);
+              
+
+static PyObject* get_func(PyObject* self, PyObject* args)
+{
+    DFError *error = NULL;
+    
+    char * concrete = NULL;
+    char * abstract = NULL;
+    
+    if (!PyArg_ParseTuple(args, "ss", &concrete, &abstract)) {
+        return NULL;
+    }    
+    
+    if (DFGetFile(concrete, abstract, &error)) {
+        Py_RETURN_TRUE;
+    }
+
+    fprintf(stderr,"%s\n",DFErrorMessage(&error));
+    DFErrorRelease(error);
+    Py_RETURN_FALSE;
+}
+
+static PyObject* put_func(PyObject* self, PyObject* args)
+{
+    DFError *error = NULL;
+    
+    char * concrete = NULL;
+    char * abstract = NULL;
+    
+    if (!PyArg_ParseTuple(args, "ss", &concrete, &abstract)) {
+        return NULL;
+    }    
+    
+    if (DFPutFile(concrete, abstract, &error)) {
+        Py_RETURN_TRUE;
+    }
+
+    fprintf(stderr,"%s\n",DFErrorMessage(&error));
+    DFErrorRelease(error);
+    Py_RETURN_FALSE;
+}
+
+static PyObject* create_func(PyObject* self, PyObject* args)
+{
+    DFError *error = NULL;
+    
+    char * concrete = NULL;
+    char * abstract = NULL;
+    
+    if (!PyArg_ParseTuple(args, "ss", &concrete, &abstract)) {
+        return NULL;
+    }    
+    
+    if (DFCreateFile(concrete, abstract, &error)) {
+        Py_RETURN_TRUE;
+    }
+
+    fprintf(stderr,"%s\n",DFErrorMessage(&error));
+    DFErrorRelease(error);
+    Py_RETURN_FALSE;
+}
+
+
+/*  define functions in module */
+static PyMethodDef dfconvertMethods[] =
+{
+     {"get", get_func, METH_VARARGS, "Create a new HTML file from input document"},
+     {"put", put_func, METH_VARARGS, "Update an existing Word document based on a modified HTML file."},
+     {"create", create_func, METH_VARARGS, "Create a new Word document from a HTML file. The Word document must not already exist."},
+     {NULL, NULL, 0, NULL}
+};
+
+
+/* module initialization */
+PyMODINIT_FUNC
+
+initdfconvert(void)
+{
+     (void) Py_InitModule("dfconvert", dfconvertMethods);
+}
diff --git a/consumers/dfwebserver/src/dfutil.c b/consumers/dfwebserver/src/dfutil.c
new file mode 100644
index 0000000..8c50aa9
--- /dev/null
+++ b/consumers/dfwebserver/src/dfutil.c
@@ -0,0 +1,47 @@
+#include <Python.h>
+
+typedef struct DFError DFError;
+void DFErrorRelease(DFError *error);
+const char *DFErrorMessage(DFError **error);
+
+int normalizeFile(const char *filename, DFError **error);
+
+static PyObject* normalize_func(PyObject* self, PyObject* args)
+{
+    DFError *dferr = NULL;
+    
+    char * filename = NULL;
+    
+    if (!PyArg_ParseTuple(args, "s", &filename)) {
+        return NULL;
+        /* if the above function returns -1, an appropriate Python exception will
+        * have been set, and the function simply returns NULL
+        */
+    }
+    
+    if (filename!=NULL) {
+        if (1 == normalizeFile(filename, &dferr)) {
+            Py_RETURN_TRUE;
+        }
+        fprintf(stderr,"%s\n",DFErrorMessage(&dferr));
+        DFErrorRelease(dferr);
+    }
+    
+    Py_RETURN_FALSE;
+}
+
+
+/*  define functions in module */
+static PyMethodDef dfutilMethods[] =
+{
+     {"normalize", normalize_func, METH_VARARGS, "evaluate the sine"},
+     {NULL, NULL, 0, NULL}
+};
+
+/* module initialization */
+PyMODINIT_FUNC
+
+initdfutil(void)
+{
+     (void) Py_InitModule("dfutil", dfutilMethods);
+}
diff --git a/consumers/dfwebserver/web/WARNING_EXPERIMENTAL b/consumers/dfwebserver/web/WARNING_EXPERIMENTAL
new file mode 100644
index 0000000..ea6861f
--- /dev/null
+++ b/consumers/dfwebserver/web/WARNING_EXPERIMENTAL
@@ -0,0 +1,7 @@
+The code in this directory is just meant to give proof of concept, and do NOT adhere to the normal apache Policy.
+
+Remark we use third party software here, that are not and will not be part of a corinthia release.
+
+This directory is not being build with the standard corinthia build.
+
+
diff --git a/consumers/dfwebserver/web/client/index.html b/consumers/dfwebserver/web/client/index.html
new file mode 100644
index 0000000..4b983f6
--- /dev/null
+++ b/consumers/dfwebserver/web/client/index.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8">
+    <script src="../../../web/client/ui.js"></script>
+    <script src="../../../web/client/uxeditor.js"></script>
+    <script src="../../../web/client/interface.js"></script>
+</head>
+<script>
+    var core = null;
+    var iface = null;
+
+    function init() {
+        var element = document.getElementById("_editor");
+        core = new UXEditor(element);
+        iface = new UXInterface(core);
+        iface.setup(function() {
+            console.log("iface setup complete");
+        }, 
+        "", 
+        "/Editor/src", "/consumers/web/client");
+    }
+    
+    function doDummyGet() {
+        document.getElementById("_content").src = "/consumers/dfwebserver/pool/sample.docx/sample.html";
+        
+    }
+</script>
+<style>
+    html,
+    body {
+        width: 100%;
+        height: 100%;
+    }
+    body {
+        margin: 0;
+        padding: 0;
+        overflow: hidden;
+        padding-top: 64px;
+    }
+    div.toolbar {
+        padding: 0;
+        border: none;
+        position: absolute;
+        top: 0px;
+        left: 0px;
+        width: 100%;
+        height: 50px;
+        background-color: #eee;
+        xvisibility: hidden;
+    }
+    div.toolbar2 {
+        border: none;
+        position: absolute;
+        top: 50px;
+        left: 0px;
+        width: 100%;
+        height: 14px;
+        background-color: #ddd;
+        xvisibility: hidden;
+        text-align: center;
+    }
+    
+    iframe.contentframe {
+        border: none;
+    }
+    div#_contentWrapper {
+        border: none;
+    }
+</style>
+
+<body onload="init()">
+
+    <div class="toolbar" id="_toolbar">
+    </div>
+    <div class="toolbar2" id="_toolbar2">
+        <a href="javascript:doDummyGet();">GET</a> 
+    </div>
+    <div style="border: 1px solid black; display: none">
+        Formatting
+        <pre id="_formatting" style="background-color: #eee">
+</pre>
+    </div>
+
+    <div id="_editor"></div>
+
+
+</body>
+
+</html>
diff --git a/consumers/web/WARNING_EXPERIMENTAL b/consumers/web/WARNING_EXPERIMENTAL
new file mode 100644
index 0000000..ea6861f
--- /dev/null
+++ b/consumers/web/WARNING_EXPERIMENTAL
@@ -0,0 +1,7 @@
+The code in this directory is just meant to give proof of concept, and do NOT adhere to the normal apache Policy.
+
+Remark we use third party software here, that are not and will not be part of a corinthia release.
+
+This directory is not being build with the standard corinthia build.
+
+
diff --git a/consumers/web/client/builtin.css b/consumers/web/client/builtin.css
new file mode 100644
index 0000000..fd6e6b6
--- /dev/null
+++ b/consumers/web/client/builtin.css
@@ -0,0 +1,36 @@
+.uxwrite-autocorrect { background-color: #c0ffc0; }
+.uxwrite-selection { background-color: rgb(201,221,238); }
+.uxwrite-spelling { background-color: rgb(255,128,128); }
+.uxwrite-match { background-color: rgb(255,255,0); }
+
+span.footnote::before {
+    content: " [ ";
+    color: #157efb;
+    font-weight: bold;
+}
+
+span.footnote::after {
+    content: " ] ";
+    color: #157efb;
+    font-weight: bold;
+}
+
+span.footnote {
+    color: #606060;
+}
+
+span.endnote::before {
+    content: " [ ";
+    color: #ca1cff;
+    font-weight: bold;
+}
+
+span.endnote::after {
+    content: " ] ";
+    color: #ca1cff;
+    font-weight: bold;
+}
+
+span.endnote {
+    color: #606060;
+}
diff --git a/consumers/web/client/images/bold-on.png b/consumers/web/client/images/bold-on.png
new file mode 100644
index 0000000..b06b225
--- /dev/null
+++ b/consumers/web/client/images/bold-on.png
Binary files differ
diff --git a/consumers/web/client/images/bold.png b/consumers/web/client/images/bold.png
new file mode 100644
index 0000000..7e68024
--- /dev/null
+++ b/consumers/web/client/images/bold.png
Binary files differ
diff --git a/consumers/web/client/images/indent.png b/consumers/web/client/images/indent.png
new file mode 100644
index 0000000..904a6aa
--- /dev/null
+++ b/consumers/web/client/images/indent.png
Binary files differ
diff --git a/consumers/web/client/images/italic-on.png b/consumers/web/client/images/italic-on.png
new file mode 100644
index 0000000..696047a
--- /dev/null
+++ b/consumers/web/client/images/italic-on.png
Binary files differ
diff --git a/consumers/web/client/images/italic.png b/consumers/web/client/images/italic.png
new file mode 100644
index 0000000..93ca99b
--- /dev/null
+++ b/consumers/web/client/images/italic.png
Binary files differ
diff --git a/consumers/web/client/images/list-none-on.png b/consumers/web/client/images/list-none-on.png
new file mode 100644
index 0000000..b4022fc
--- /dev/null
+++ b/consumers/web/client/images/list-none-on.png
Binary files differ
diff --git a/consumers/web/client/images/list-none.png b/consumers/web/client/images/list-none.png
new file mode 100644
index 0000000..09b2555
--- /dev/null
+++ b/consumers/web/client/images/list-none.png
Binary files differ
diff --git a/consumers/web/client/images/list-ol-on.png b/consumers/web/client/images/list-ol-on.png
new file mode 100644
index 0000000..01e44f3
--- /dev/null
+++ b/consumers/web/client/images/list-ol-on.png
Binary files differ
diff --git a/consumers/web/client/images/list-ol.png b/consumers/web/client/images/list-ol.png
new file mode 100644
index 0000000..7555fbd
--- /dev/null
+++ b/consumers/web/client/images/list-ol.png
Binary files differ
diff --git a/consumers/web/client/images/list-ul-on.png b/consumers/web/client/images/list-ul-on.png
new file mode 100644
index 0000000..a034288
--- /dev/null
+++ b/consumers/web/client/images/list-ul-on.png
Binary files differ
diff --git a/consumers/web/client/images/list-ul.png b/consumers/web/client/images/list-ul.png
new file mode 100644
index 0000000..22d6e50
--- /dev/null
+++ b/consumers/web/client/images/list-ul.png
Binary files differ
diff --git a/consumers/web/client/images/outdent.png b/consumers/web/client/images/outdent.png
new file mode 100644
index 0000000..582af61
--- /dev/null
+++ b/consumers/web/client/images/outdent.png
Binary files differ
diff --git a/consumers/web/client/images/underline-on.png b/consumers/web/client/images/underline-on.png
new file mode 100644
index 0000000..250268a
--- /dev/null
+++ b/consumers/web/client/images/underline-on.png
Binary files differ
diff --git a/consumers/web/client/images/underline.png b/consumers/web/client/images/underline.png
new file mode 100644
index 0000000..9e0564c
--- /dev/null
+++ b/consumers/web/client/images/underline.png
Binary files differ
diff --git a/consumers/web/client/index.html b/consumers/web/client/index.html
new file mode 100644
index 0000000..175cec7
--- /dev/null
+++ b/consumers/web/client/index.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <script src="ui.js"></script>
+  <script src="uxeditor.js"></script>
+  <script src="interface.js"></script>
+</head>
+<script>
+var core = null;
+var iface = null;
+
+function init()
+{
+    var element = document.getElementById("_editor");
+    core = new UXEditor(element);
+    iface = new UXInterface(core);
+    iface.setup(function() {
+        console.log("iface setup complete");
+    }, "sample.html", "../../../Editor/src", ".");
+//    core.callbacks = iface.callbacks;
+//    core.setup(function() {
+//        core.op.cursor.test(3,4,5);
+//    });
+}
+</script>
+<style>
+html, body { width: 100%; height: 100%; }
+
+body {
+    margin: 0;
+    padding: 0;
+    overflow: hidden;
+    padding-top: 64px;
+}
+
+div.toolbar {
+    border: none;
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    width: 100%;
+    height: 64px;
+    background-color: #eee;
+    xvisibility: hidden;
+}
+
+iframe.contentframe {
+    border: none;
+}
+
+div#_contentWrapper {
+    border: none;
+}
+</style>
+<body onload="init()">
+
+<div class="toolbar" id="_toolbar">
+  <!--
+    <span id="_btnBold">Bold</span>
+    &nbsp;|&nbsp;
+    <span id="_btnItalic">Italic</span>
+    &nbsp;|&nbsp;
+    <span id="_btnUnderline">Underline</span>
+    &nbsp;|&nbsp;
+    <span id="_btnListNone">No list</span>
+    &nbsp;|&nbsp;
+    <span id="_btnListUL">UL</span>
+    &nbsp;|&nbsp;
+    <span id="_btnListOL">OL</span>
+    &nbsp;|&nbsp;
+    <span id="_btnListOutdent">Outdent</span>
+    &nbsp;|&nbsp;
+    <span id="_btnListIndent">Indent</span>
+    &nbsp;|&nbsp;
+  -->
+</div>
+<div style="border: 1px solid black; display: none">
+Formatting
+<pre id="_formatting" style="background-color: #eee">
+</pre>
+</div>
+
+<div id="_editor"></div>
+
+
+</body>
+</html>
diff --git a/consumers/web/client/interface.js b/consumers/web/client/interface.js
new file mode 100644
index 0000000..ec2deb2
--- /dev/null
+++ b/consumers/web/client/interface.js
@@ -0,0 +1,371 @@
+// 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.
+
+function UXInterface(core)
+{
+    var self = this;
+    var elemFormatting = document.getElementById("_formatting");
+    var setupDone = false;
+    var callbacks = null;
+    var lastReceivedFormatting = {};
+    var formatting = {};
+    var cursorDiv = null;
+    var dragging = false;
+    var buttons = {};
+
+    function hideCursor()
+    {
+        if (cursorDiv != null) {
+            core.cdoc.body.removeChild(cursorDiv);
+            cursorDiv = null;
+        }
+    }
+
+    function hideOverlaysWhileExecuting(fun)
+    {
+        if (cursorDiv != null)
+            cursorDiv.style.visibility = "hidden";
+        try {
+            return fun();
+        }
+        finally {
+            if (cursorDiv != null)
+                cursorDiv.style.visibility = "visible";
+        }
+    }
+
+    // DOM event handlers
+    function mouseDown(event)
+    {
+        var x = event.clientX;
+        var y = event.clientY;
+
+        var targetClass = event.target.getAttribute("class");
+        console.log("mouseDown "+event.clientX+", "+event.clientY+", class "+targetClass);
+        console.log("body height = "+core.cdoc.body.getBoundingClientRect().height);
+
+        dragging = true;
+        hideOverlaysWhileExecuting(function() {
+            core.op.selection.dragSelectionBegin(x,y,false);
+        });
+
+        updateFormatting();
+        event.preventDefault();
+    }
+
+    function mouseUp(event)
+    {
+        dragging = false;
+        updateFormatting();
+        event.preventDefault();
+    }
+
+    function mouseMove(event)
+    {
+        if (dragging) {
+            core.op.selection.dragSelectionUpdate(event.clientX,event.clientY,false);
+            updateFormatting();
+        }
+        event.preventDefault();
+    }
+
+
+    function keyDown(event)
+    {
+        if (event.keyCode == 13) {
+            core.op.cursor.enterPressed();
+            updateFormatting();
+            event.preventDefault();
+        }
+        else if (event.keyCode == 8) {
+            core.op.cursor.deleteCharacter();
+            updateFormatting();
+            event.preventDefault();
+        }
+    }
+
+    function keyUp(event)
+    {
+        if ((event.keyCode == 13) || (event.keyCode == 8))
+            event.preventDefault();
+    }
+
+    function keyPress(event)
+    {
+        core.op.cursor.insertCharacter(String.fromCharCode(event.charCode));
+        updateFormatting();
+        event.preventDefault();
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+    function markFormattingDirty()
+    {
+        var changes = {};
+        for (var key in formatting)
+            changes[key] = formatting[key];
+
+        // When calling updateFormatting(), we have to ensure that any properties we
+        // wish to clear are present in the object, but set to null. While the following
+        // code might appear to do nothing, what it's actually searching for are missing
+        // properties, which it explicitly adds as null.
+        for (var key in lastReceivedFormatting) {
+            console.log("lastReceivedFormatting["+JSON.stringify(key)+"] = "+
+                        JSON.stringify(lastReceivedFormatting[key]));
+            if (changes[key] == null)
+                changes[key] = null;
+        }
+
+        console.log("caling applyFormattingChanges: "+JSON.stringify(changes));
+        core.op.formatting.applyFormattingChanges(null,changes);
+        updateFormatting();
+    }
+
+    function toggleBold()
+    {
+        console.log("toggleBold()");
+        if (formatting["font-weight"] != null)
+            delete formatting["font-weight"];
+        else
+            formatting["font-weight"] = "bold";
+        markFormattingDirty();
+    }
+
+    function toggleItalic()
+    {
+        console.log("toggleItalic()");
+        if (formatting["font-style"] != null)
+            delete formatting["font-style"];
+        else
+            formatting["font-style"] = "italic";
+        markFormattingDirty();
+    }
+
+    function toggleUnderline()
+    {
+        console.log("toggleUnderline()");
+        if (formatting["text-decoration"] != null)
+            delete formatting["text-decoration"];
+        else
+            formatting["text-decoration"] = "underline";
+        markFormattingDirty();
+    }
+
+    function pressListUL()
+    {
+        if (formatting["-uxwrite-in-ul"] != null)
+            core.op.lists.clearList();
+        else
+            core.op.lists.setUnorderedList();
+        markFormattingDirty();
+    }
+
+    function pressListOL()
+    {
+        if (formatting["-uxwrite-in-ol"] != null)
+            core.op.lists.clearList();
+        else
+            core.op.lists.setOrderedList();
+        markFormattingDirty();
+    }
+
+    function pressListOutdent()
+    {
+        core.op.lists.decreaseIndent();
+        markFormattingDirty();
+    }
+
+    function pressListIndent()
+    {
+        var inUL = formatting["-uxwrite-in-ul"];
+        var inOL = formatting["-uxwrite-in-ol"];
+        if (!inUL && !inOL)
+            core.op.lists.setUnorderedList();
+        else
+            core.op.lists.increaseIndent();
+        markFormattingDirty();
+    }
+
+
+
+
+
+    function retrieveStyles()
+    {
+        console.log("retrieveStyles: this = "+this.constructor.name);
+        console.log("retrieveStyles: self = "+self.constructor.name);
+    }
+
+    function updateOutline()
+    {
+    }
+
+    function shallowCopy(object)
+    {
+        var result = {};
+        for (var key in object)
+            result[key] = object[key];
+        return result;
+    }
+
+    function updateFormatting()
+    {
+        console.log("updateFormatting()");
+        lastReceivedFormatting = core.op.formatting.getFormatting();
+        formatting = shallowCopy(lastReceivedFormatting);
+        console.log("formatting = "+JSON.stringify(formatting));
+        while (elemFormatting.firstChild != null)
+            elemFormatting.removeChild(elemFormatting.firstChild);
+        for (var key in formatting) {
+            var str = key+" = "+formatting[key];
+            elemFormatting.appendChild(document.createTextNode(str+"\n"));
+        }
+
+        var inUL = formatting["-uxwrite-in-ul"];
+        var inOL = formatting["-uxwrite-in-ol"];
+
+        buttons.bold.setValue(formatting["font-weight"] != null);
+        buttons.italic.setValue(formatting["font-style"] != null);
+        buttons.underline.setValue(formatting["text-decoration"] != null);
+        buttons.listUL.setValue(inUL);
+        buttons.listOL.setValue(inOL);
+    }
+
+    function setup(completion, iframeSrc, editorSrc, resources)
+    {
+        var toolbar = document.getElementById("_toolbar");
+
+        buttons.bold = new Button(resources + "/images/bold");
+        buttons.italic = new Button(resources + "/images/italic");
+        buttons.underline = new Button(resources + "/images/underline");
+        buttons.listUL = new Button(resources + "/images/list-ul");
+        buttons.listOL = new Button(resources + "/images/list-ol");
+        buttons.listOutdent = new Button(resources + "/images/outdent");
+        buttons.listIndent = new Button(resources + "/images/indent");
+
+        toolbar.appendChild(buttons.bold.element);
+        toolbar.appendChild(buttons.italic.element);
+        toolbar.appendChild(buttons.underline.element);
+        toolbar.appendChild(buttons.listUL.element);
+        toolbar.appendChild(buttons.listOL.element);
+        toolbar.appendChild(buttons.listOutdent.element);
+        toolbar.appendChild(buttons.listIndent.element);
+
+        core.callbacks = callbacks;
+        core.setup(function() {
+            setupDone = true;
+
+            retrieveStyles();
+            updateOutline();
+            updateFormatting();
+
+            buttons.bold.onMouseDown = toggleBold;
+            buttons.italic.onMouseDown = toggleItalic;
+            buttons.underline.onMouseDown = toggleUnderline;
+            buttons.listUL.onMouseDown = pressListUL;
+            buttons.listOL.onMouseDown = pressListOL;
+            buttons.listOutdent.onMouseDown = pressListOutdent;
+            buttons.listIndent.onMouseDown = pressListIndent;
+
+            core.cdoc.documentElement.addEventListener("mousedown",mouseDown,true);
+            core.cdoc.documentElement.addEventListener("mouseup",mouseUp,true);
+            core.cdoc.documentElement.addEventListener("mousemove",mouseMove,true);
+
+            document.body.addEventListener("keydown",keyDown,true);
+            document.body.addEventListener("keyup",keyUp,true);
+            document.body.addEventListener("keypress",keyPress,true);
+
+            if (completion != null)
+                completion();
+        }, iframeSrc, editorSrc, resources);
+    }
+
+    callbacks = {
+        debug: function(str) {
+            console.log("cb debug("+JSON.stringify(str)+")");
+        },
+        error: function(error,type) {
+            console.log("cb error("+JSON.stringify(error)+","+
+                                    JSON.stringify(type)+")");
+        },
+        addOutlineItem: function(itemId,type,title) {
+            console.log("cb addOutlineItem("+JSON.stringify(itemId)+","+
+                                             JSON.stringify(type)+","+
+                                             JSON.stringify(title)+")");
+        },
+        updateOutlineItem: function(itemId,title) {
+            console.log("cb updateOutlineItem("+JSON.stringify(itemId)+","+
+                                                JSON.stringify(title)+")");
+        },
+        removeOutlineItem: function(itemId) {
+            console.log("cb removeOutlineItem("+JSON.stringify(itemId)+")");
+        },
+        outlineUpdated: function() {
+            console.log("cb outlineUpdated()");
+        },
+        setCursor: function(x,y,width,height) {
+            console.log("cb setCursor("+x+","+y+","+width+","+height+")");
+
+
+            if (cursorDiv == null) {
+                cursorDiv = document.createElement("div");
+                core.cdoc.body.appendChild(cursorDiv);
+            }
+
+            var iframeRect = core.iframe.getBoundingClientRect();
+            cursorDiv.style.display = "block";
+            cursorDiv.style.position = "absolute";
+            cursorDiv.style.backgroundColor = "blue";
+            cursorDiv.style.left = x+"px";
+            cursorDiv.style.top = y+"px";
+            cursorDiv.style.width = width+"px";
+            cursorDiv.style.height = height+"px";
+            cursorDiv.setAttribute("class","cursor");
+        },
+        setSelectionHandles: function(x1,y1,height1,x2,y2,height2) {
+            console.log("cb setSelectionHandles("+x1+","+y1+","+height1+","+
+                                                  x2+","+y2+","+height2+")");
+            hideCursor();
+        },
+        setTableSelection: function(x,y,width,height) {
+            console.log("cb setTableSelection("+x+","+y+","+width+","+height+")");
+            hideCursor();
+        },
+        setSelectionBounds: function(left,top,right,bottom) {
+            console.log("cb setSelectionBounds("+left+","+top+","+right+","+bottom+")");
+        },
+        clearSelectionHandlesAndCursor: function() {
+            console.log("cb clearSelectionHandlesAndCursor()");
+            hideCursor();
+        },
+        updateAutoCorrect: function() {
+            console.log("cb updateAutoCorrect()");
+        },
+    };
+
+    this.setup = setup;
+}
diff --git a/consumers/web/client/sample.html b/consumers/web/client/sample.html
new file mode 100644
index 0000000..c7a584a
--- /dev/null
+++ b/consumers/web/client/sample.html
@@ -0,0 +1,1130 @@
+<!DOCTYPE html>
+
+<html lang="en-AU">
+<head>
+  <meta charset="utf-8">
+  <meta name="generator" content="UX Write 2.0.2 (build 4b4faea); iOS 7.1">
+
+  <title></title>
+  <style>
+blockquote {
+    font-style: italic;
+  }
+
+  body {
+    counter-reset: h1 h2 h3 h4 h5 h6 figure table;
+    font-family: Palatino;
+    xmargin: 10%;
+    text-align: justify;
+  }
+
+  caption {
+    caption-side: bottom;
+    counter-increment: table;
+  }
+
+  caption.Unnumbered {
+    counter-increment: table 0;
+  }
+
+  caption.Unnumbered::before, figcaption.Unnumbered::before {
+    content: "";
+  }
+
+  caption::before {
+    content: "Table " counter(table) ": ";
+  }
+
+  figcaption {
+    counter-increment: figure;
+  }
+
+  figcaption.Unnumbered {
+    counter-increment: figure 0;
+  }
+
+  figcaption::before {
+    content: "Figure " counter(figure) ": ";
+  }
+
+  figure {
+    margin-bottom: 12pt;
+    margin-left: auto;
+    margin-right: auto;
+    margin-top: 12pt;
+    text-align: center;
+  }
+
+  h1 {
+    counter-increment: h1;
+    counter-reset: h2 h3 h4 h5 h6;
+  }
+
+  h1.Unnumbered, h2.Unnumbered, h3.Unnumbered, h4.Unnumbered, h5.Unnumbered, h6.Unnumbered {
+  }
+
+  h1::before {
+    content: counter(h1) " ";
+  }
+
+  h2 {
+    color: #585958;
+    counter-increment: h2;
+    counter-reset: h3 h4 h5 h6;
+  }
+
+  h2::before {
+    content: counter(h1) "." counter(h2) " ";
+  }
+
+  h3 {
+    counter-increment: h3;
+    counter-reset: h4 h5 h6;
+  }
+
+  h3::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) " ";
+  }
+
+  h4 {
+    counter-increment: h4;
+    counter-reset: h5 h6;
+  }
+
+  h4::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) " ";
+  }
+
+  h5 {
+    counter-increment: h5;
+    counter-reset: h6;
+  }
+
+  h5::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) " ";
+  }
+
+  h6 {
+    counter-increment: h6;
+  }
+
+  h6::before {
+    content: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) " ";
+  }
+
+  nav.listoffigures::before {
+    content: "List of Figures";
+    display: block;
+    font-size: 2em;
+    font-weight: bold;
+    margin-bottom: .67em;
+    margin-top: .67em;
+  }
+
+  nav.listoftables::before {
+    content: "List of Tables";
+    display: block;
+    font-size: 2em;
+    font-weight: bold;
+    margin-bottom: .67em;
+    margin-top: .67em;
+  }
+
+  nav.tableofcontents::before {
+    content: "Contents";
+    display: block;
+    font-size: 2em;
+    font-weight: bold;
+    margin-bottom: .67em;
+    margin-top: .67em;
+  }
+
+  p {
+    line-height: 166%;
+  }
+
+  p.abstract {
+    font-style: italic;
+    margin-left: 20%;
+    margin-right: 20%;
+  }
+
+  p.author {
+    font-size: 18pt;
+    text-align: center;
+  }
+
+  p.NoSpacing {
+    margin: 0%;
+  }
+
+  p.SpecialNote {
+    color: red;
+    font-weight: bold;
+    text-align: center;
+  }
+
+  p.Tip {
+    background-color: #eeeeee;
+    border: hidden;
+    border-radius: 10px;
+    margin-left: 5%;
+    margin-right: 5%;
+    padding: 10pt;
+  }
+
+  p.Title {
+    font-size: 36pt;
+    font-weight: bold;
+    margin-bottom: 24pt;
+    text-align: center;
+    text-decoration: underline;
+  }
+
+  p.toc1 {
+    margin-bottom: 6pt;
+    margin-left: 0pt;
+    margin-top: 12pt;
+  }
+
+  p.toc2 {
+    margin-bottom: 6pt;
+    margin-left: 24pt;
+    margin-top: 6pt;
+  }
+
+  p.toc3 {
+    margin-bottom: 6pt;
+    margin-left: 48pt;
+    margin-top: 6pt;
+  }
+
+  table {
+    border-collapse: collapse;
+    margin-left: auto;
+    margin-right: auto;
+  }
+
+  td > :first-child, th > :first-child {
+    margin-top: 0;
+  }
+
+  td > :last-child, th > :last-child {
+    margin-bottom: 0;
+  }
+
+  td, th {
+    border: 1px solid black;
+  }
+  </style>
+</head>
+
+<body>
+
+  <h1 id="item9">Introduction</h1>
+
+  <p>UX Write is designed for long-form, professional writing tasks such as
+  reports, research papers, theses, and books. With an emphasis on technical
+  and academic writing, it provides tools to work with the <i>content</i> and
+  <i>structure</i> of your document separately from its <i>presentation</i>.
+  The latter is controlled by <i>styles</i>, such as headings, normal
+  paragraphs, and the document title.</p>
+
+  <h2 id="item19">What you see is what you mean</h2>
+
+  <p>The design philosophy of UX Write is “what you see is what you mean”, or
+  WYSIWYM. By separating content from presentation, and making the logical
+  structure of documents explicit, it is possible for the layout and rendering
+  of text to adapt to the output medium. This means your documents look just as
+  good on a 30“ desktop monitor as they do on a 7” tablet or the printed
+  page.</p>
+
+  <p>The structure of your document — such as the hierarchy of section headings
+  — also enables other useful features. A table of contents is generated
+  automatically, without you having to manually update text or page numbers.
+  Cross-references can be added and kept up-to-date as section numbers change.
+  The outline view, accessible from the toolbar, displays all the sections,
+  figures, and tables in your document, allowing you to navigate around
+  easily.</p>
+
+  <p>A contrasting approach is “what you see is what you get”, or WYSIWYG,
+  supported by programs like Microsoft Word and Pages. This attempts to
+  replicate the precise layout of a printed page on screen during editing,
+  regardless of whether you're using a desktop computer or a mobile phone.
+  While useful for some purposes, we believe it's the wrong approach for a
+  mobile word processor. UX Write is unapologetically WYSIWYM, and is optimised
+  for readability and ease-of-use across both iPhone and iPad.</p>
+
+  <p class="Tip">If you've got this document open for editing, take a moment
+  now to explore the document outline (third toolbar button from right). Try
+  adjusting the text size in the “Look &amp; feel” section of the settings menu
+  (second from right) to suit your reading preferences. Rotate your screen and
+  watch as the text reflows.</p>
+
+  <h2 id="item17">File formats</h2>
+
+  <p>The native file format of UX Write is HTML — the language of the web. You
+  can view HTML documents on any device or operating system out there, and
+  publish online without any need for file conversion. If you open a Microsoft
+  Word document, it is temporarily converted to HTML for editing, and then
+  saved back again afterwards. Any parts of the document that could not be
+  converted, such as embedded spreadsheets, are preserved in the original Word
+  document.</p>
+
+  <h1 id="item8">Basic features</h1>
+
+  <h2 id="item11">Accessing your Documents</h2>
+
+  <p>You can store your documents on your device only — under
+  “My iPad” or “My iPhone” — or sync them with a cloud service such as Dropbox.
+  In the former case, you can transfer files to your computer using <a href=
+  "http://support.apple.com/kb/HT4094">iTunes file sharing</a>, and in the
+  latter case you can either access your files through the respective service's
+  website, or by installing the service's software on your computer. Box,
+  Dropbox, Google Drive, and Microsoft OneDrive all have clients available for
+  Windows and Mac which you can install for free.</p>
+
+  <p>File synchronisation happens automatically. Whenever a
+  document is saved, it is uploaded&nbsp; in the background, while you continue
+  working. If you have your computer set up for syncing, you will usually see
+  these changes appear within a few seconds. Within UX Write, you can check for
+  updates to existing documents using the refresh button.</p>
+
+  <p>If you're working offline, you can still add and change documents in any
+  of the Box, Dropbox, Google Drive, OneDrive or WebDAV locations you have set
+  up. When you have an Internet connection available again, just launch UX
+  Write, and it will attempt to upload the documents. To move, copy, or delete
+  documents, simply tap the “Edit” button in the file browser.</p>
+
+  <p class="Tip"><b>Tip:</b> We recommend creating and storing all your
+  documents on Dropbox, because it keeps backup copies of every version
+  uploaded for 30 days. You can view and recover old versions of your document
+  if the need arises — see Section <a href="#item10">4.1</a>.</p>
+
+  <h2 id="item4">Editing</h2>
+
+  <p>Text editing works in much the same way as in any other iOS app, but with
+  a few enhancements:</p>
+
+  <ul>
+    <li>
+      <p>An extra row of keys above the keyboard provides access to common
+      punctuation symbols</p>
+    </li>
+
+    <li>
+      <p>The two leftmost keys let you move the cursor or select text by
+      holding them down to bring up a virtual trackpad. Swipe with one finger
+      to move slowly, and two fingers to move faster.</p>
+    </li>
+
+    <li>
+      <p>The formatting key, when held down, replaces the other top-row keys
+      with keys for basic formatting options like bold, italic, and lists</p>
+    </li>
+
+    <li>
+      <p>The autocorrect key allows you to confirm or revert the latest
+      autocorrect replacement (see Section <a href="#item2">2.5</a> for more
+      details)</p>
+    </li>
+
+    <li>
+      <p>You can triple-tap anywhere in the text to select the whole
+      paragraph</p>
+    </li>
+  </ul>
+
+  <p>Note: The keyboard extensions are only available on the iPad.</p>
+
+  <p>UX Write also includes full support for external bluetooth keyboards, and
+  supports all of the standard keyboard shortcuts:</p>
+
+  <table style="width: 100%;" id="item7">
+    <caption>
+      Keyboard shortcuts
+    </caption>
+
+    <colgroup>
+      <col width="50%">
+      <col width="50%">
+    </colgroup>
+
+    <tbody>
+      <tr>
+        <td>
+          <p>Cmd-B</p>
+        </td>
+
+        <td>
+          <p>Bold</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-I</p>
+        </td>
+
+        <td>
+          <p>Italic</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-U</p>
+        </td>
+
+        <td>
+          <p>Underline</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-X</p>
+        </td>
+
+        <td>
+          <p>Cut</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-C</p>
+        </td>
+
+        <td>
+          <p>Copy</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-V</p>
+        </td>
+
+        <td>
+          <p>Paste</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-A</p>
+        </td>
+
+        <td>
+          <p>Select all</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Option-Left/Right</p>
+        </td>
+
+        <td>
+          <p>Move back or forward one word</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Option-Up/Down</p>
+        </td>
+
+        <td>
+          <p>Move up or down one paragraph</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-Left/Right</p>
+        </td>
+
+        <td>
+          <p>Move to start or end of line</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Cmd-Up/Down</p>
+        </td>
+
+        <td>
+          <p>Move to start of end of document</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <p>Shift-Arrow key (+ Cmd or Option)</p>
+        </td>
+
+        <td>
+          <p>Any of the above, but for selection</p>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+
+  <h2 id="item5">Styles</h2>
+
+  <p>All formatting in UX Write, with the exception of
+  bold,&nbsp;italic, underline and lists, is controlled using <i>styles</i> —
+  such as headings and normal paragraphs. A style serves two purposes:</p>
+
+  <ol>
+    <li>
+      <p>It determines the <i>formatting</i> of the text, such
+      as the font, colour, and paragraph alignment. When a style is modified,
+      all text associated with that style automatically adopts the new
+      formatting, making it easy to ensure consistent presentation throughout
+      your document.</p>
+    </li>
+
+    <li>
+      <p>It indicates the <i>purpose</i> of a piece of text,
+      such as a heading or title. UX Write uses this information for various
+      purposes, such as building a table of contents, displaying the outline
+      view, and determining the possible targets for cross-references.</p>
+    </li>
+  </ol>
+
+  <p>UX Write Basic Edition provides a plain set of built-in styles for
+  headings, block quotes, a document title, and normal text. UX Write
+  Professional Edition allows you to modify the appearance of these built-in
+  styles, as well as create your own; see Section&nbsp;<a href=
+  "#item29">3.1</a> for details.</p>
+
+  <h2 id="item6">Auto correct</h2>
+
+  <p>Automatic correction of typing mistakes can sometimes lead to unexpected
+  results, since no piece of software can accurately guess what you meant to
+  type in every case. When UX Write makes a correction, it highlights it in
+  green, and gives you the opportunity to confirm whether or not it has made
+  the right replacement.</p>
+
+  <p>Tapping on a highlighted word brings up a menu that allows you to accept
+  the correction, revert to the original, or bring up a list of more
+  suggestions, with the option to add the word to the custom dictionary. Any
+  substitutions you explicitly accept are remembered by UX Write, and will
+  occur automatically the next time you make the same typing mistake. You can
+  access the custom dictionary and list of automatic substitutions via the
+  settings menu.</p>
+
+  <h2 id="item2">Outline Navigation</h2>
+
+  <p>You can use the outline view — the third toolbar button
+  from the right — to view the structure of your document and quickly jump
+  between sections. This is particularly useful for large documents, where
+  scrolling would be a hassle.</p>
+
+  <p>The outline view is based on the headings, figures, and
+  tables in your document. For headings to be included, you must mark them as
+  such using the formatting menu. Tables and figures are always included. As
+  you modify your document by adding, removing, or changing content, the
+  outline is automatically kept up-to-date. UX Write Professional Edition also
+  allows you to edit the outline — see Section <a href="#item30">3.4</a> for
+  details.</p>
+
+  <p>In landscape mode on the iPad, you can “pin” the outline to
+  the left of your screen, and it will be displayed alongside your document. To
+  pin or unpin it, use the button at the top of the outline. To hide the
+  outline when it is pinned, press the 'X' button.</p>
+
+  <p>The outline view corresponds directly to what in the table
+  of contents, list of figures, and list of tables, if you have added any of
+  these to your document. See Section&nbsp;<a href="#item32">3.9</a> for
+  details.</p>
+
+  <h1 id="item27">Professional features</h1>
+
+  <p>This section describes features that are only available in
+  UX Write Professional Edition. You can upgrade to this by either purchasing
+  it outright, or by subscribing on a monthly basis. Go to the settings menu
+  and select “View upgrade options” to see details.</p>
+
+  <h2 id="item29">Styles</h2>
+
+  <p>Styles, introduced in Section&nbsp;<a href=
+  "#item5">2.3</a>, define both the formatting and purpose of text in your
+  document. Heading styles, for instance, denote the document outline, and are
+  used for constructing the table of contents. Each style can have different
+  formatting properties, such as fonts, colours, margins, paragraph alignment,
+  borders, and more.</p>
+
+  <p>Using styles enables you to achieve consistent formatting
+  throughout your entire document. Instead of manually changing formatting on a
+  case-by-case basis — as many other word processors encourage you to do — you
+  adjust a style once and it applies to all text in the document associated
+  with the style. This is useful for ensuring your document complies with
+  requirements from your organisation or publisher.</p>
+
+  <p>UX Write provides a number of built-in styles, based on
+  those present in HTML. There are six levels of headings, in addition
+  to&nbsp;normal paragraphs and block quotes. You can change the way any of
+  these are formatted, and also add your own custom styles for specific
+  purposes. For example, this document contains a “Tip” style, which appears as
+  a light-grey box with rounded corners, and left and right margins that place
+  it in the center of the page.</p>
+
+  <p>To manage styles, go to the formatting menu, and select
+  “Edit Styles”. This will bring up the style manager, with a list of styles on
+  the left, and formatting properties on either the top or right of the screen
+  (depending on your screen orientation).</p>
+
+  <p>To edit an existing style, simply select it in the list, and change any of
+  the formatting properties. You will see a preview displayed below the
+  controls that shows an example piece of text as it would be displayed in the
+  document.</p>
+
+  <p>To add a new style, scroll down to the bottom of the list and tap next to
+  the green '+' button. Type in your style name and press enter. You can now
+  set up the formatting for this style, and subsequently select it from the
+  formatting menu in the editor.</p>
+
+  <p>Direct formatting is still available if you want it, via
+  the item near the bottom of the formatting menu. This gives you the same
+  properties as are available in the style editor, but the changes only apply
+  to the current selection.</p>
+
+  <p>Styles you create in UX Write are compatible with Word, and
+  you can also edit and use the styles in Word itself.</p>
+
+  <p class="Tip"><b>Tip:</b> If you want to re-use your styles with multiple
+  documents, you can set up a template for creating new documents. See Section
+  <a href="#item15">3.13</a> for details.</p>
+
+  <h2 id="item39">Formatting</h2>
+
+  <p>There are two ways to adjust formatting:</p>
+
+  <ul>
+    <li>
+      <p><b>Styles.</b> You can select these from the formatting
+      menu; they apply at the paragraph level. Generally, you should use styles
+      to control formatting, as this provides structural information about the
+      document (in the case of headings), and allows you to easily change
+      formatting throughout the whole document for any given style.</p>
+    </li>
+
+    <li>
+      <p><b>Direct formatting.</b> You can also select this from
+      the formatting menu; this is intended for “one-off” cases where you wish
+      to format a particular piece of text without defining a style, such as
+      highlighting something important. You have access to all the same
+      formatting options as you do for styles. Direct formatting corresponds to
+      what you would see in the toolbar of Microsoft Word; we've deliberately
+      de-emphasised it in the user interface to encourage the use of
+      styles.</p>
+    </li>
+  </ul>
+
+  <p>All of the formatting properties directly correspond to
+  those of CSS (Cascading Style Sheets), the web standard used in conjunction
+  with HTML. In most cases, the CSS formatting properties UX Write supports can
+  also be translated directly to those of Microsoft Word; the main exception is
+  that Word has a slightly different way of handling paragraph borders and
+  margins.</p>
+
+  <p>Formatting properties are divided into two categories:
+  <i>text</i> and <i>paragraph</i>. Text properties, in the case of direct
+  formatting, can be applied to only a portion of a paragraph. The rest apply
+  to the paragraph as a whole.</p>
+
+  <h2 id="item26">Document structure</h2>
+
+  <p>Most formal documents like reports and books are divided
+  into multiple levels of <b>sections</b>, with <b>cross-references</b> between
+  them, and a <b>table of contents</b> at the front. Styles are key to
+  achieving this, because the program needs to be told which pieces of text are
+  headings — it can't simply guess that “18 point bold” means a second-level
+  heading. By using styles to mark all your headings, you can take advantage of
+  the following features:</p>
+
+  <ul>
+    <li>
+      <p>Table of contents (Insert menu)</p>
+    </li>
+
+    <li>
+      <p>Cross-references (Insert menu)</p>
+    </li>
+
+    <li>
+      <p>Automatic numbering</p>
+    </li>
+
+    <li>
+      <p>Outline editor (Outline button on toolbar)</p>
+    </li>
+  </ul>
+
+  <p>Whenever a section number changes as a result of changes
+  earlier in the document, its number is automatically updated, as are those of
+  all references that point to it, and the table of contents. The same is true
+  of figures and tables. When you print or generate a PDF, page numbers are
+  automatically calculated for you and included in the table of contents.</p>
+
+  <h2 id="item30">Outline editing</h2>
+
+  <p>You can rearrange and delete sections in the outline by
+  pressing the “Edit button”. To change the order of sections, tap and drag the
+  section name to your desired position. To delete an item, just press the red
+  button on the left, and confirm by pressing the “Delete” button that appears.
+  All changes you make in the outline editor are immediately reflected in the
+  document, including updates to numbering.</p>
+
+  <h2 id="item35">Find and replace</h2>
+
+  <p>On iPad, a search bar is visible at the top of the screen,
+  and you can just type in your search term and hit enter. Tap the down arrow
+  to view options, including replacement text. On iPhone, the search bar and
+  options are accessible via the settings menu.</p>
+
+  <p>By default, searching will look for the exact text you have
+  entered, with case sensitivity determined by whether you have selected that
+  option. Alternatively, you can search and replace text using <i>regular
+  expressions</i>, which allow you to enter patterns that can match multiple
+  snippets of text. Regular expression support is mainly intended for advanced
+  users, such as programmers, who are already familiar with the concept. If you
+  would like to learn more, we recommend the tutorial at at&nbsp;<a href=
+  "http://regexone.com">regexone.com</a>.</p>
+
+  <h2 id="item36">Spell checking</h2>
+
+  <p>The spell checking option will search through your document
+  and highlight any instances of words it finds which are not in the system or
+  custom dictionaries.</p>
+
+  <p>The language&nbsp;used is determined by the following three
+  settings, in order:</p>
+
+  <ul>
+    <li>
+      <p>Language for the current document (Settings &gt; This
+      Document &gt; Language)</p>
+    </li>
+
+    <li>
+      <p>Default language for UX Write (Settings &gt;
+      Application &gt; Language)</p>
+    </li>
+
+    <li>
+      <p>System language (set in the Settings app of your iPad
+      or iPhone)</p>
+    </li>
+  </ul>
+
+  <p>There is currently no support for handling multiple
+  languages in a single document. The set of languages available for spell
+  checking is determined by the built-in dictionaries provided by the operating
+  system, which as of 7.1 are:</p>
+
+  <ul>
+    <li>
+      <p class="NoSpacing">Danish</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Dutch</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">English (Australia)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">English (Canada)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">English (United Kingdom)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">English (United States)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">French</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">German</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Italian</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Portuguese (Brazil)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Portuguese (Portugal)</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Russian</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Spanish</p>
+    </li>
+
+    <li>
+      <p class="NoSpacing">Swedish</p>
+    </li>
+  </ul>
+
+  <h2 id="item37">Word count</h2>
+
+  <p>You can view the word count for your document from the
+  settings menu. This also includes the total number of characters and
+  paragraphs.</p>
+
+  <h2 id="item31">Automatic numbering</h2>
+
+  <p>UX Write can assign numbers to all headings, figures, and
+  tables automatically. For headings, you can turn this on using the “Heading
+  numbering” option in the settings menu. For figures and tables, you can set
+  this on an individual basis either at insertion time, or by tapping on the
+  item and selecting “Figure” or “Table” in the popup menu.</p>
+
+  <p>Numbering is updated automatically as the document changes.
+  If you add or remove a heading, change it's nesting level (e.g.
+  from&nbsp;Heading 2 to Heading 1), or move sections around using the outline
+  editor, the numbers will be updated to reflect the changes. The same is also
+  true for figures and tables.</p>
+
+  <p>All cross-references, plus the table of contents, list of
+  figures, and list of tables (if present) are also kept up to date whenever
+  the numbers change. This ensures that you never have out-of-date references
+  and you don't have to remember to manually update other parts of the
+  document.&nbsp;</p>
+
+  <h2 id="item32">Table of contents</h2>
+
+  <p>While it's possible to manually create a table of contents
+  in any word processor, doing so is tedious, particularly when keeping all the
+  section titles and page numbers up to date. In UX Write, inserting a table of
+  contents causes it to be constructed automatically based on the headings,
+  just like the outline view described in Section&nbsp;<a href=
+  "#item30">3.4</a>. And like automatic numbering and the outline view, every
+  time you add or remove a section, or change its title, the table of contents
+  automatically updates to reflect the change.</p>
+
+  <p>Page numbers are <i>not</i> displayed in the table of
+  contents during editing or when saving as a HTML file, as neither has any
+  concept of distinct pages. When you print or export to PDF, the correct page
+  numbers will be filled in for you. There's no need to do this manually.</p>
+
+  <p>You can also insert a list of figures or list of tables,
+  which work similarly to the table of contents. The text shown in these comes
+  from the captions, with the numbers shown in the same way as section numbers.
+  As with the table of contents, these are always kept in sync with the rest of
+  document.</p>
+
+  <p>If your document is in HTML format, the table of contents,
+  list of figures, and list of tables will appear as links that can be clicked
+  to jump to the appropriate section when viewed in a web browser.</p>
+
+  <h2 id="item1">Cross-references</h2>
+
+  <p>You can insert a cross-reference to any section heading,
+  figure, or table in your document. When you select this option from the
+  insert menu, you'll see a document outline (the same as in the outline view),
+  and can select a target of the cross-reference.</p>
+
+  <p>References appear as hyperlinks in the document. When you
+  tap on one, you'll have the option to either go to the target of the
+  reference, or change it to point to a different section, figure, or
+  table.</p>
+
+  <p>If your reference is to a numbered heading, figure, or
+  table, the number will be updated whenever that of its target changes. If the
+  target is not numbered, the reference will contain the text instead, and will
+  also update whenever the text changes.</p>
+
+  <h2 id="item3">Footnotes and endnotes</h2>
+
+  <p>Because UX Write uses a continuous layout for editing, in
+  which the document is not divided into separate pages, footnotes are
+  displayed inline with the text<span class="footnote">A footnote looks like
+  this</span>. For consistency, and to avoid the need to jump back and forth
+  between the content and the end of the document, endnotes are handled in the
+  same way<span class="endnote">An endnote looks like this</span>.</p>
+
+  <p>HTML does not have any explicit support for either
+  footnotes or endnotes, in the sense that there is no &lt;footnote&gt; element
+  that can clearly indicate its purpose. UX Write uses &lt;span&gt; elements
+  with a class of “footnote” or “endnote” to represent these.</p>
+
+  <p>Microsoft Word documents <i>do</i> have explicit support
+  for both, so when editing a .docx file, UX Write will save them in the
+  appropriate format. When you open the document in Word, you'll see footnotes
+  at the bottom of the page, and endnotes at the end of the document.</p>
+
+  <p>To have footnotes and endnotes appear in their correct
+  positions in a print or PDF output, you must use the LaTeX typesetting option
+  (see Section&nbsp;<a href="#item23">3.12</a>). WebKit does not have the
+  capabilities to support pagination features.</p>
+
+  <h2 id="item23">Printing and PDF export</h2>
+
+  <p>Two different typesetting systems are supported for
+  producing print and PDF output. You can choose between these using the
+  “Typesetting” option under the settings menu:</p>
+
+  <ul>
+    <li>
+      <p><b>WebKit</b> (recommended). Safari's layout engine,
+      optimised for on-screen rendering of HTML content.</p>
+
+      <p>This is the layout engine used for displaying your
+      documents during editing, and the PDF files it generates match exactly
+      the formatting you see on screen; though line breaks will be different
+      for the printed page.</p>
+    </li>
+
+    <li>
+      <p><b>LaTeX</b> (new). The de-facto standard in many
+      scientific disciplines, optimised for high-quality typography and
+      paginated output.</p>
+
+      <p>Support for LaTeX is new in 2.0. Currently, only
+      limited formatting options are supported, and English is the only
+      supported language. We'll be improving this throughout the 2.x release
+      cycle, with support for other languages and many other features, such as
+      equations, bibliographies, and headers/footers.</p>
+    </li>
+  </ul>
+
+  <p>Of these two, only LaTeX is capable of correctly
+  typesetting footnotes and endnotes, as well as other pagination-dependent
+  features we'll be adding in the future. If you print or export to PDF using
+  WebKit, footnotes and endnotes will appear inline with the text, as they do
+  during editing.</p>
+
+  <h2 id="item15">Creating Templates</h2>
+
+  <p>Often you'll want to create a series of documents which all have a
+  consistent look and feel, based on styles that you have set up, as described
+  in Section <a href="#item29">3.1</a>. While UX Write does not have a “proper”
+  template feature (yet), you can get the same effect by creating a normal
+  document with your desired settings, and treating that as a starting point
+  for new documents.</p>
+
+  <p>To create a template:</p>
+
+  <ol>
+    <li>
+      <p>Create a new document, calling it “My template” (or whatever you
+      like)</p>
+    </li>
+
+    <li>
+      <p>Open the document and use the style manager to change the default
+      fonts, colours, and other formatting properties that you want</p>
+    </li>
+
+    <li>
+      <p>Create any custom styles that you will use regularly — e.g. “Title” or
+      “Abstract”</p>
+    </li>
+  </ol>
+
+  <p>To create a new document based on a template:</p>
+
+  <ol>
+    <li>
+      <p>Tap and hold on the template document in the file manager</p>
+    </li>
+
+    <li>
+      <p>Select “Duplicate”</p>
+    </li>
+
+    <li>
+      <p>Type in the name for your new document</p>
+    </li>
+
+    <li>
+      <p>Open the new document and start writing</p>
+    </li>
+  </ol>
+
+  <p>We'll be adding a more sophisticated mechanism for browsing and previewing
+  template files, along with a few nice samples, in a future update.</p>
+
+  <h1 id="item13">Common Tasks</h1>
+
+  <h2 id="item10">Dropbox Versioning</h2>
+
+  <p>One of the best features of Dropbox is that it automatically keeps old
+  versions of every file that's uploaded to it. It's always been possible to
+  log into the Dropbox website and access these old versions via their web
+  interface, but now you can do it directly from within UX Write itself.</p>
+
+  <p>If you ever need to recover an older version of a document, simply tap and
+  hold on it in the file browser, and select “Versions” in the popup menu. You
+  can then browse through all the versions that Dropbox has kept, and restore
+  the one you want. UX Write autosaves every three minutes, so if you're
+  connected to the Internet while you're working, you'll have regular snapshots
+  of your documents.<b></b></p>
+
+  <h2 id="item12">Converting from HTML to docx</h2>
+
+  <p>If you've upgraded from a previous version of UX Write and wish to convert
+  your HTML documents to .docx so they can be used with Microsoft Word, you can
+  do so as follows:</p>
+
+  <ul>
+    <li>
+      <p>Tap and hold on the document in the file browser</p>
+    </li>
+
+    <li>
+      <p>Select <b>Convert to</b> <b>docx</b></p>
+    </li>
+  </ul>
+
+  <p>Note that due to differences between the two file formats, there may be
+  some loss of formatting during the transition — for example, the rounded
+  borders used in the “Tip” style in this document can't be represented in
+  docx. For this reason, the original HTML file will be kept as a backup.</p>
+
+  <h1 id="item16">Troubleshooting</h1>
+
+  <h2 id="item18">Reporting Bugs</h2>
+
+  <p>If you encounter a crash in UX Write, you will be asked if you would like
+  to submit a bug report. This report includes a crash log indicating exactly
+  where in the program the problem occurred, as well as a redacted copy of your
+  document in which all text and images have been removed. An email window will
+  appear where you can add comments about what happened, and the bug report
+  will be sent to us when you hit “Send”. You can CC yourself a copy for
+  reference if you like.</p>
+
+  <p><b>If we can't reproduce it, we can't fix it.</b> Many people send in bug
+  reports containing just the crash log. Often, we can to determine from this
+  what went wrong, but this isn't always the case. To increase the chances of
+  us being able to fix the problem, try to provide a detailed description of
+  what you were doing right before the crash occurred.</p>
+
+  <p>The best bug reports provide a clear set of steps that explain how to
+  reproduce the problem. During beta testing of 2.0, one particularly helpful
+  person even used iPad screen recording software to make a video demonstrating
+  how to trigger a bug, edited the video in iMovie, and added an audio track
+  with narration to explain what was going on. You certainly don't have to go
+  to this much effort, but a few simple instructions in your email which
+  explain how to reliably reproduce a problem will help a lot.</p>
+
+  <p>If you encounter any other issues that do not involve a crash, such as
+  formatting inconsistencies or strange user interface behaviour, just select
+  the <b>Submit bug report</b>&nbsp;option from the settings menu and send us a
+  note. Remember, the more information, the better.</p>
+
+  <p>The app store does not provide developers with any way to directly respond
+  to bug reports included in reviews. You can say whatever you want, but
+  <b>please also let us know about your problem</b> in case we need to ask you
+  for more information in order to fix it.</p>
+
+  <h2 id="item14">Purchase and Subscription</h2>
+
+  <p>Every time you install something from the app store, iOS
+  includes a <i>receipt file</i> which is accessible to the app. This file
+  includes information about the version number of the app that you originally
+  downloaded, as well as any in-app payments you have made. UX Write looks at
+  this file to determine whether or not to enable the features in the
+  professional edition.</p>
+
+  <p>If you buy a new iPad or iPhone and install UX Write on it
+  via iTunes, this receipt file might not be present. If you have purchased or
+  subscribed to the app, it's necessary for UX Write to request a copy of the
+  receipt file from the app store so it can verify your upgrade status. You can
+  do this either from the intro screen shown at first launch, or by selecting
+  “Reactivate existing upgrade” from the settings menu.</p>
+
+  <p>If you originally purchased UX Write prior to the release
+  of version 2.0 (when it was a paid-only app), you should automatically have
+  access to the professional edition. The way UX Write determines this is by
+  looking at the receipt file and checking what the version number of the app
+  was at the time of your purchase. So if you see the app running as basic
+  edition, select “Reactivate existing upgrade” from the settings menu.</p>
+
+  <p>If you have any problems with upgrades or payments,
+  <a href="http://www.uxproductivity.com/support">please contact us</a>.</p>
+
+  <h2 id="item20">The Field Update Problem</h2>
+
+  <p>If you open a .docx file in Word after editing it in UX Write, you'll see
+  the following message:</p>
+
+  <blockquote>
+    “This document contains fields that may refer to other files. Do you want
+    to update the fields in this document?”
+  </blockquote>
+
+  <p>When you see this message, just click <b>Yes</b> (or press the <b>Y</b>
+  key).</p>
+
+  <p>Sadly, this is a symptom of a design flaw in Word, and is something only
+  Microsoft can fix. Unlike UX Write, Word does not keep the table of contents,
+  cross references, or figure/table numbers (all collectively known as
+  <b>Fields</b>) up to date automatically. Instead, it forces you to manually
+  tell it when it to update the fields after you have made changes to your
+  document.</p>
+
+  <p>Despite the fact that UX Write never actually produces fields that refer
+  to other files, this message is still displayed in every version of Word that
+  we have tested with, including Word 2013. The only way we could prevent such
+  a dialog from appearing is to store a setting in the document that tells Word
+  that there is no need to update the fields — but this would simply leave you
+  with an invalid table of contents and incorrect cross-references. While we've
+  done our best to ensure that UX Write provides the best user experience
+  within the app itself, we're not able to fix Word.</p>
+
+  <h2 id="item22">Opening .doc files</h2>
+
+  <p>Microsoft Word has used a number of different file formats over the years,
+  and UX Write only supports the most recent version, .docx, which is a modern,
+  XML-based, well-documented open standard. The older .doc format is a
+  proprietary and very complex binary file format that would take a minimum of
+  six months to support. We've decided that time is better spent on other
+  useful features instead.</p>
+
+  <p>If you have a .doc file that you wish to edit in UX Write, you can convert
+  it to .docx by opening it in any recent version of Word (2007 and later), and
+  using “Save as” to convert it to docx. Doing so will maintain all of the
+  content and formatting, and provide exactly the same experience when working
+  with the document in Word itself. You will then have your document in a much
+  more portable format, and be able to edit it in Word, UX Write, and other
+  word processors such as LibreOffice.</p>
+
+  <h1 id="item28">More information</h1>
+
+  <p>If you have a question that isn't answered here, check out
+  our <a href="http://www.uxproductivity.com/support">support website</a> for
+  more info. We also maintain a <a href=
+  "http://blog.uxproductivity.com">blog</a> discussing the development of the
+  app and new features that are in the works. Many of our posts discuss various
+  questions people have had about UX Write and may provide you with a deeper
+  understanding of why certain aspects of the app are the way they are.</p>
+
+  <p>We value any feedback you have about the app, and you can
+  send it to us any time via the option on the settings menu. We receive a
+  <i>lot</i> of email, and can't guarantee to respond individually or add every
+  requested feature, but we certainly take into account your feedback when
+  deciding on priorities for future updates.</p>
+</body>
+</html>
diff --git a/consumers/web/client/ui.js b/consumers/web/client/ui.js
new file mode 100644
index 0000000..08e263b
--- /dev/null
+++ b/consumers/web/client/ui.js
@@ -0,0 +1,75 @@
+// 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.
+
+function Button(imagePrefix)
+{
+    var self = this;
+    var mouseInside = false;
+
+    this.element = document.createElement("div");
+    this.element.style.display = "inline-block";
+    this.element.style.width = "20px";
+    this.element.style.height = "20px";
+    this.element.style.padding = "10px";
+    this.element.style.margin = "8px";
+    this.element.style.borderWidth = "4px";
+    this.element.style.borderRadius = "4px";
+    this.element.addEventListener("mousedown",function() {
+        if (self.onMouseDown != null)
+            self.onMouseDown();
+    });
+    this.element.addEventListener("mouseover",function() {
+        mouseInside = true;
+        updateBackgroundColor();
+    });
+    this.element.addEventListener("mouseout",function() {
+        mouseInside = false;
+        updateBackgroundColor();
+    });
+
+
+    this.img = document.createElement("img");
+    this.img.style.width = "20px";
+    this.img.style.height = "20px";
+    this.element.appendChild(this.img);
+
+
+    this.value = false;
+
+    this.setValue = function(newValue)
+    {
+        this.value = newValue;
+        if (this.value)
+            this.img.setAttribute("src",imagePrefix+"-on.png");
+        else
+            this.img.setAttribute("src",imagePrefix+".png");
+        updateBackgroundColor();
+    }
+
+    function updateBackgroundColor()
+    {
+        var color = "transparent";
+        if (mouseInside)
+            color = "#ccc";
+        else if (self.value)
+            color = "#000";
+        self.element.style.backgroundColor = color;
+        self.element.style.borderColor = color;
+    }
+
+    this.setValue(false);
+}
diff --git a/consumers/web/client/uxeditor.js b/consumers/web/client/uxeditor.js
new file mode 100644
index 0000000..45fe5e4
--- /dev/null
+++ b/consumers/web/client/uxeditor.js
@@ -0,0 +1,320 @@
+// 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.
+
+var IMPL_DIR = "../../../Editor/src";
+var RESOURCES_DIR = ".";
+
+function UXEditor(element)
+{
+    var self = this;
+    var doc = element.ownerDocument;
+    var iframeWrapper = null;
+    var iframe = null;
+    var setupCompletion = null;
+    var pendingScripts = {};
+    var doneScriptInit = false;
+
+    console.log("UXEditor: element = "+element);
+    console.log("UXEditor: doc = "+doc);
+
+    function setup(completion, iframeSrc, editorSrc, resources)
+    {
+        setupCompletion = completion;
+        IMPL_DIR = editorSrc;
+        RESOURCES_DIR = resources;
+        iframeWrapper = doc.createElement("div");
+//        iframeWrapper.setAttribute("id","_contentWrapper");
+        iframeWrapper.setAttribute("tabindex","0");
+        iframeWrapper.style.border = "none";
+
+        iframe = doc.createElement("iframe");
+        iframe.setAttribute("id","_content");
+        iframe.addEventListener("load",iframeLoaded);
+        iframe.setAttribute("src", iframeSrc); //"sample.html";
+        iframe.style.border = "none";
+//        iframe.setAttribute("class","contentframe");
+
+        iframeWrapper.appendChild(iframe);
+        element.appendChild(iframeWrapper);
+
+        self.iframeWrapper = iframeWrapper;
+        self.iframe = iframe;
+
+        window.onresize = updateIFrameSize;
+        updateIFrameSize();
+    }
+
+    function updateIFrameSize()
+    {
+        var width = window.innerWidth;
+        var height = window.innerHeight - 64;
+
+        iframe.style.width = width+"px";
+        iframe.style.height = height+"px";
+        iframeWrapper.style.width = width+"px";
+        iframeWrapper.style.height = height+"px";
+    }
+
+    function iframeLoaded()
+    {
+        console.log("iframe loaded");
+        self.cdoc = iframe.contentDocument;
+        self.cwin = iframe.contentWindow;
+
+        var javascriptFiles = ["first.js",
+                               "ElementTypes.js",
+                               "AutoCorrect.js",
+                               "ChangeTracking.js",
+                               "Clipboard.js",
+                               "Cursor.js",
+                               "DOM.js",
+                               "Editor.js",
+                               "Equations.js",
+                               "Figures.js",
+                               "Formatting.js",
+                               "Hierarchy.js",
+                               "Input.js",
+                               "Lists.js",
+                               "Main.js",
+                               "Metadata.js",
+                               "NodeSet.js",
+                               "Outline.js",
+                               "Position.js",
+                               "PostponedActions.js",
+                               "Range.js",
+                               "Selection.js",
+                               "3rdparty/showdown/showdown.js",
+                               "Scan.js",
+                               "StringBuilder.js",
+                               "Styles.js",
+                               "Tables.js",
+                               "Text.js",
+                               "traversal.js",
+                               "types.js",
+                               "UndoManager.js",
+                               "util.js",
+                               "Viewport.js"];
+
+        // We first create all the script objects and set their onload properties. Only *after*
+        // that do we actually add them to the document. This ensures that pendingScripts will
+        // only ever become empty after all the scripts have definitely loaded.
+        var scripts = [];
+        for (var i = 0; i < javascriptFiles.length; i++) {
+            var src = IMPL_DIR+"/"+javascriptFiles[i];
+            var script = document.createElement("script");
+            script.setAttribute("src",src);
+            pendingScripts[src] = true;
+            script.onload = function(e) { scriptLoaded(e.target); }
+            scripts.push(script);
+        }
+
+        // Now add the script elements to the document, triggering their load
+        for (var i = 0; i < scripts.length; i++)
+            self.cdoc.head.appendChild(scripts[i]);
+    }
+
+    function scriptLoaded(script)
+    {
+        delete pendingScripts[script.getAttribute("src")];
+        console.log("loadedScript: "+script.getAttribute("src")+
+                    "; remaining = "+Object.keys(pendingScripts).length);
+        if (Object.keys(pendingScripts).length > 0)
+            return;
+
+        if (!doneScriptInit) {
+            doneScriptInit = true;
+            console.log("Now we should init");
+
+            self.cwin.Main_init(800,150, RESOURCES_DIR + "/builtin.css",false);
+
+            if (setupCompletion != null)
+                setupCompletion();
+        }
+    }
+
+    function invokeCallbacks()
+    {
+        var messages = JSON.parse(self.cwin.Editor_getBackMessages());
+
+        if (self.callbacks == null)
+            return;
+        console.log("messages.length = "+messages.length);
+        for (var i = 0; i < messages.length; i++) {
+            var name = messages[i][0];
+            var args = messages[i].slice(1);
+            if ((self.callbacks != null) && (self.callbacks[name] != null))
+                self.callbacks[name].apply(null,args);
+        }
+    }
+
+    function wrap(name)
+    {
+        return function() {
+            var argsArray = [];
+            var args = new Array();
+            console.log("arguments.length = "+arguments.length);
+            for (var i = 0; i < arguments.length; i++) {
+                args.push(arguments[i]);
+            }
+            var res = self.cwin.Main_execute(function() {
+                return self.cwin[name].apply(null,args);
+            });
+            invokeCallbacks();
+
+            // Ensure we have a completely separate copy of the data
+            if (res == null) {
+                return null;
+            }
+            else {
+                var str = JSON.stringify(res);
+                return JSON.parse(str);
+            }
+        }
+    }
+
+    var op = {
+        clipboard: {
+            cut: wrap("Clipboard_cut"),
+            copy: wrap("Clipboard_copy"),
+            pasteText: wrap("Clipboard_pasteText"),
+            pasteHTML: wrap("Clipboard_pasteHTML"),
+        },
+        cursor: {
+            positionCursor: wrap("Cursor_positionCursor"),
+            getCursorPosition: wrap("Cursor_getCursorPosition"),
+            insertReference: wrap("Cursor_insertReference"),
+            insertLink: wrap("Cursor_insertLink"),
+            insertCharacter: wrap("Cursor_insertCharacter"),
+            deleteCharacter: wrap("Cursor_deleteCharacter"),
+            enterPressed: wrap("Cursor_enterPressed"),
+            getPrecedingWord: wrap("Cursor_getPrecedingWord"),
+            getLinkProperties: wrap("Cursor_getLinkProperties"),
+            setLinkProperties: wrap("Cursor_setLinkProperties"),
+            setReferenceTarget: wrap("Cursor_setReferenceTarget"),
+            insertFootnote: wrap("Cursor_insertFootnote"),
+            insertEndnote: wrap("Cursor_insertEndnote"),
+            test: wrap("Cursor_test"),
+        },
+        figures: {
+            insertFigure: wrap("Figures_insertFigure"),
+            getSelectedFigureId: wrap("Figures_getSelectedFigureId"),
+            getProperties: wrap("Figures_getProperties"),
+            setProperties: wrap("Figures_setProperties"),
+            getGeometry: wrap("Figures_getGeometry"),
+        },
+        formatting: {
+            getFormatting: wrap("Formatting_getFormatting"),
+            applyFormattingChanges: wrap("Formatting_applyFormattingChanges"),
+        },
+        input: {
+        },
+        lists: {
+            increaseIndent: wrap("Lists_increaseIndent"),
+            decreaseIndent: wrap("Lists_decreaseIndent"),
+            clearList: wrap("Lists_clearList"),
+            setUnorderedList: wrap("Lists_setUnorderedList"),
+            setOrderedList: wrap("Lists_setOrderedList"),
+        },
+        main: {
+            getLanguage: wrap("Main_getLanguage"),
+            setLanguage: wrap("Main_setLanguage"),
+            setGenerator: wrap("Main_setGenerator"),
+            prepareForSave: wrap("Main_prepareForSave"),
+            getHTML: wrap("Main_getHTML"),
+            isEmptyDocument: wrap("Main_isEmptyDocument"),
+        },
+        outline: {
+            getOutline: wrap("Outline_getOutline"),
+            moveSection: wrap("Outline_moveSection"),
+            deleteItem: wrap("Outline_deleteItem"),
+            goToItem: wrap("Outline_goToItem"),
+            scheduleUpdateStructure: wrap("Outline_scheduleUpdateStructure"),
+            setTitle: wrap("Outline_setTitle"),
+            setNumbered: wrap("Outline_setNumbered"),
+            insertTableOfContents: wrap("Outline_insertTableOfContents"),
+            insertListOfFigures: wrap("Outline_insertListOfFigures"),
+            insertListOfTables: wrap("Outline_insertListOfTables"),
+            setPrintMode: wrap("Outline_setPrintMode"),
+            examinePrintLayout: wrap("Outline_examinePrintLayout"),
+            detectSectionNumbering: wrap("Outline_detectSectionNumbering"),
+            findUsedStyles: wrap("Outline_findUsedStyles"),
+        },
+        scan: {
+            reset: wrap("Scan_reset"),
+            next: wrap("Scan_next"),
+            addMatch: wrap("Scan_addMatch"),
+            showMatch: wrap("Scan_showMatch"),
+            replaceMatch: wrap("Scan_replaceMatch"),
+            removeMatch: wrap("Scan_removeMatch"),
+            goToMatch: wrap("Scan_goToMatch"),
+        },
+        selection: {
+            update: wrap("Selection_update"),
+            selectAll: wrap("Selection_selectAll"),
+            selectParagraph: wrap("Selection_selectParagraph"),
+            selectWordAtCursor: wrap("Selection_selectWordAtCursor"),
+            dragSelectionBegin: wrap("Selection_dragSelectionBegin"),
+            dragSelectionUpdate: wrap("Selection_dragSelectionUpdate"),
+            moveStartLeft: wrap("Selection_moveStartLeft"),
+            moveStartRight: wrap("Selection_moveStartRight"),
+            moveEndLeft: wrap("Selection_moveEndLeft"),
+            moveEndRight: wrap("Selection_moveEndRight"),
+            setSelectionStartAtCoords: wrap("Selection_setSelectionStartAtCoords"),
+            setSelectionEndAtCoords: wrap("Selection_setSelectionEndAtCoords"),
+            setTableSelectionEdgeAtCoords: wrap("Selection_setTableSelectionEdgeAtCoords"),
+            print: wrap("Selection_print"),
+        },
+        styles: {
+            getCSSText: wrap("Styles_getCSSText"),
+            setCSSText: wrap("Styles_setCSSText"),
+            getParagraphClass: wrap("Styles_getParagraphClass"),
+            setParagraphClass: wrap("Styles_setParagraphClass"),
+        },
+        tables: {
+            insertTable: wrap("Tables_insertTable"),
+            addAdjacentRow: wrap("Tables_addAdjacentRow"),
+            addAdjacentColumn: wrap("Tables_addAdjacentColumn"),
+            removeAdjacentRow: wrap("Tables_removeAdjacentRow"),
+            removeAdjacentColumn: wrap("Tables_removeAdjacentColumn"),
+            clearCells: wrap("Tables_clearCells"),
+            mergeCells: wrap("Tables_mergeCells"),
+            splitSelection: wrap("Tables_splitSelection"),
+            getSelectedTableId: wrap("Tables_getSelectedTableId"),
+            getProperties: wrap("Tables_getProperties"),
+            setProperties: wrap("Tables_setProperties"),
+            setColWidths: wrap("Tables_setColWidths"),
+            getGeometry: wrap("Tables_getGeometry"),
+        },
+        undoManager: {
+            getLength: wrap("UndoManager_getLength"),
+            getIndex: wrap("UndoManager_getIndex"),
+            setIndex: wrap("UndoManager_setIndex"),
+            undo: wrap("UndoManager_undo"),
+            redo: wrap("UndoManager_redo"),
+            newGroup: wrap("UndoManager_newGroup"),
+            groupType: wrap("UndoManager_groupType"),
+        },
+    };
+
+    self.setup = setup;
+    self.op = op;
+    self.callbacks = null;
+    self.cdoc = null;
+    self.cwin = null;
+    self.iframeWrapper = null;
+    self.iframe = null;
+}
diff --git a/external/README.txt b/external/README.txt
index efbbfb4..7c5ad65 100644
--- a/external/README.txt
+++ b/external/README.txt
@@ -1,4 +1,4 @@
-README.txt 1.1.0                     UTF-8
+README.txt 1.1.1                     UTF-8
 
                         EXTERNAL DOWNLOADS SETUP AND USE
                         ================================
@@ -131,7 +131,6 @@
 copies of DLLs from external\download\bin\
 
   iconv.dll
-  exit
   libjpeg-9.dll
   libpng16-16.dll
   libtiff-5.dll
@@ -177,6 +176,7 @@
 
 REVISIONS
 
+ 1.1.1 2015-01-12-19:24 Stray word removed from the list of DLLs in Section 4
  1.1.0 2015-01-08-21:20 Updated Draft with complete coverage
  1.0.0 2015-01-08-15:21 Initial Draft replacement of the original README.txt
 
diff --git a/external/external.txt b/external/external.txt
index 4846554..d6fad4e 100644
--- a/external/external.txt
+++ b/external/external.txt
@@ -70,6 +70,15 @@
 
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
+ TODO:
+  * Make headway on issue COR-21 to either reconcile it or figure out what
+    to do with "malformed" Zip files that create empty directories (a
+    Unix-ism).
+
+ 1.0.1 2015-02-14-11:59 Add TODO
+       Note that the *.sh files are not listed in this manifest.  They are
+       now also removed, since they conflict with changes made to where
+       the externals are unzipped.
  1.0.0 2015-01-08-21:14 Create initial version to account for the files in
        the external\ folder
 
diff --git a/external/extract_downloads.sh b/external/extract_downloads.sh
deleted file mode 100755
index 38b9d6e..0000000
--- a/external/extract_downloads.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-
-set -e
-
-mkdir packages
-
-mkdir packages/SDL2
-mkdir packages/SDL2_image
-mkdir packages/iconv
-mkdir packages/libxml2
-mkdir packages/zlib
-
-(cd packages/SDL2 && unzip ../../download/SDL2-devel-2.0.3-VC.zip)
-(cd packages/SDL2_image && unzip ../../download/SDL2_image-devel-2.0.0-VC.zip)
-(cd packages/iconv && unzip ../../download/iconv-1.9.2.win32.zip)
-(cd packages/libxml2 && unzip ../../download/libxml2-2.7.8.win32.zip)
-(cd packages/zlib && unzip ../../download/zlib128-dll.zip)
-chmod -R u+w packages/zlib
-
-for i in bin lib include; do
-    if [ ! -d $i ]; then
-        mkdir $i
-    fi
-done
-
-mv packages/SDL2/SDL2-2.0.3/include/* include
-mv packages/SDL2/SDL2-2.0.3/lib/x86/*.lib lib
-mv packages/SDL2/SDL2-2.0.3/lib/x86/*.dll bin
-
-mv packages/SDL2_image/SDL2_image-2.0.0/include/* include
-mv packages/SDL2_image/SDL2_image-2.0.0/lib/x86/*.lib lib
-mv packages/SDL2_image/SDL2_image-2.0.0/lib/x86/*.dll bin
-
-mv packages/iconv/iconv-1.9.2.win32/include/* include
-mv packages/iconv/iconv-1.9.2.win32/lib/* lib
-mv packages/iconv/iconv-1.9.2.win32/bin/* bin
-
-mv packages/libxml2/libxml2-2.7.8.win32/include/* include
-mv packages/libxml2/libxml2-2.7.8.win32/lib/* lib
-mv packages/libxml2/libxml2-2.7.8.win32/bin/* bin
-
-mv packages/zlib/include/* include
-mv packages/zlib/lib/* lib
-mv packages/zlib/*.dll bin
-
-rm -rf packages
diff --git a/external/fetch_downloads.sh b/external/fetch_downloads.sh
deleted file mode 100755
index c03b9b3..0000000
--- a/external/fetch_downloads.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-set -e
-if [ ! -d download ]; then
-    mkdir download
-fi
-
-URLS="http://zlib.net/zlib128-dll.zip \
-      ftp://ftp.zlatkovic.com/libxml/iconv-1.9.2.win32.zip \
-      ftp://ftp.zlatkovic.com/libxml/libxml2-2.7.8.win32.zip \
-      https://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip \
-      https://www.libsdl.org/projects/SDL_image/release/SDL2_image-devel-2.0.0-VC.zip"
-
-cd download
-for url in $URLS; do
-    if [ ! -f $(basename $url) ]; then
-        wget $url
-    fi
-done
-
-cd ..
diff --git a/sample/README.txt b/sample/README.txt
new file mode 100644
index 0000000..8de6b4c
--- /dev/null
+++ b/sample/README.txt
@@ -0,0 +1,3 @@
+The 'code' directory contains binding code examples.  Please read the WARNINGS file.
+
+The 'documents' directory contains sample documents for conversion.
diff --git a/sample/code/objc_bindings/EDJSInterface.h b/sample/code/objc_bindings/EDJSInterface.h
new file mode 100644
index 0000000..b4183de
--- /dev/null
+++ b/sample/code/objc_bindings/EDJSInterface.h
@@ -0,0 +1,367 @@
+// 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.
+
+// IMPORTANT NOTE: This code does not work in it's current form,
+// and exists for illustrative purposes only. It is an excerpt
+// from the UX Write source code indented to show how the bindings
+// between Objective C and JavaScript are implemented, both in
+// terms of calling *in* to JavaScript, and calling *out* of
+// JavaScript (that is, callback functions).
+//
+// (see further comments in EDJSInterface.m)
+
+#import <Foundation/Foundation.h>
+#import <CoreGraphics/CoreGraphics.h>
+
+@class JSAutoCorrect;
+@class JSChangeTracking;
+@class JSClipboard;
+@class JSCursor;
+@class JSEquations;
+@class JSFigures;
+@class JSFormatting;
+@class JSInput;
+@class JSLists;
+@class JSMain;
+@class JSMetadata;
+@class JSOutline;
+@class JSPreview;
+@class JSScan;
+@class JSSelection;
+@class JSStyles;
+@class JSTables;
+@class JSUndoManager;
+@class JSViewport;
+@class EDScanParagraph;
+
+@interface JSError : NSError
+
+@property (copy, readonly) NSString *type;
+@property (copy, readonly) NSString *message;
+@property (copy, readonly) NSString *operation;
+@property (copy, readonly) NSString *html;
+
+@end
+
+@protocol JSInterfaceDelegate
+
+- (void)jsAddOutlineItem:(NSString *)itemId type:(NSString *)type title:(NSString *)title;
+- (void)jsUpdateOutlineItem:(NSString *)itemId title:(NSString *)title;
+- (void)jsRemoveOutlineItem:(NSString *)itemId;
+- (void)jsOutlineUpdated;
+- (void)jsSetCursorX:(int)x y:(int)y width:(int)width height:(int)height;
+- (void)jsSetSelectionHandlesX1:(int)x1 y1:(int)y1 height1:(int)height1
+                             x2:(int)x2 y2:(int)y2 height2:(int)height2;
+- (void)jsSetTableSelectionX:(int)x y:(int)y width:(int)width height:(int)height;
+- (void)jsSetSelectionBoundsLeft:(int)left top:(int)top right:(int)right bottom:(int)bottom;
+- (void)jsClearSelectionHandlesAndCursor;
+- (void)jsUpdateAutoCorrect;
+
+@end
+
+@protocol JSEvaluator
+
+- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
+
+@end
+
+@interface JSInterface : NSObject
+
+@property (weak) NSObject<JSEvaluator> *evaluator;
+@property (weak) NSObject<JSInterfaceDelegate> *delegate;
+@property (assign) BOOL jsInitialised;
+@property (strong) JSAutoCorrect *autoCorrect;
+@property (strong) JSChangeTracking *changeTracking;
+@property (strong) JSClipboard *clipboard;
+@property (strong) JSCursor *cursor;
+@property (strong) JSEquations *equations;
+@property (strong) JSFigures *figures;
+@property (strong) JSFormatting *formatting;
+@property (strong) JSInput *input;
+@property (strong) JSLists *lists;
+@property (strong) JSMain *main;
+@property (strong) JSMetadata *metadata;
+@property (strong) JSOutline *outline;
+@property (strong) JSPreview *preview;
+@property (strong) JSScan *scan;
+@property (strong) JSSelection *selection;
+@property (strong) JSStyles *styles;
+@property (strong) JSTables *tables;
+@property (strong) JSUndoManager *undoManager;
+@property (strong) JSViewport *viewport;
+@property (copy) NSString *currentOperation;
+@property (strong) JSError *error;
+@property (assign) BOOL documentModified;
+
+- (JSInterface *)initWithEvaluator:(NSObject<JSEvaluator> *)evaluator;
+- (BOOL)initJavaScriptWidth:(int)width textScale:(int)textScale cssURL:(NSString *)cssURL
+             clientRectsBug:(BOOL)clientRectsBug;
+- (void)printStatistics;
+
+@end
+
+@interface JSModule : NSObject
+
+@property (assign) JSInterface *js;
+
+- (JSModule *)initWithJS:(JSInterface *)js;
+
+@end
+
+// Functions implemented in AutoCorrect.js
+
+@interface JSAutoCorrect : JSModule
+
+- (void)correctPreceding:(int)numChars word:(NSString *)replacement confirmed:(BOOL)confirmed;
+- (NSDictionary *)getCorrection;
+- (NSDictionary *)getCorrectionCoords;
+- (void)acceptCorrection;
+- (void)replaceCorrection:(NSString *)replacement;
+
+@end
+
+// Functions implemented in ChangeTracking.js
+
+@interface JSChangeTracking : JSModule
+- (BOOL)showChanges;
+- (BOOL)trackChanges;
+- (void)setShowChanges:(BOOL)showChanges;
+- (void)setTrackChanges:(BOOL)trackChanges;
+@end
+
+// Functions implemented in Clipboard.js
+
+@interface JSClipboard : JSModule
+- (NSDictionary *)clipboardCut;
+- (NSDictionary *)clipboardCopy;
+- (void)pasteHTML:(NSString *)html;
+- (void)pasteText:(NSString *)text;
+@end
+
+// Functions implemented in Cursor.js
+
+@interface JSCursor : JSModule
+- (NSString *)positionCursorX:(int)x y:(int)y wordBoundary:(BOOL)wordBoundary;
+- (CGRect)getCursorPosition;
+- (void)moveLeft;
+- (void)moveRight;
+- (void)moveToStartOfDocument;
+- (void)moveToEndOfDocument;
+- (void)insertReference:(NSString *)itemId;
+- (void)insertLinkWithText:(NSString *)text URL:(NSString *)URL;
+- (void)insertCharacter:(unichar)character allowInvalidPos:(BOOL)allowInvalidPos;
+- (void)deleteCharacter;
+- (void)enterPressed;
+- (NSString *)getPrecedingWord;
+- (NSDictionary *)getLinkProperties;
+- (void)setLinkProperties:(NSDictionary *)properties;
+- (void)setReferenceTarget:(NSString *)itemId;
+- (void)insertFootnote:(NSString *)content;
+- (void)insertEndnote:(NSString *)content;
+@end
+
+// Functions implemented in Equations.js
+
+@interface JSEquations : JSModule
+- (void)insertEquation;
+@end
+
+// Functions implemented in Figures.js
+
+@interface JSFigures : JSModule
+- (void)insertFigure:(NSString *)filename width:(NSString *)width
+            numbered:(BOOL)numbered caption:(NSString *)caption;
+- (NSString *)getSelectedFigureId;
+- (NSDictionary *)getProperties:(NSString *)itemId;
+- (void)setProperties:(NSString *)itemId width:(NSString *)width src:(NSString *)src;
+- (NSDictionary *)getGeometry:(NSString *)itemId;
+@end
+
+// Functions implemented in Formatting.js
+
+@interface JSFormatting : JSModule
+- (NSDictionary *)getFormatting;
+- (void)applyFormattingChangesStyle:(NSString *)style properties:(NSDictionary *)properties;
+@end
+
+// Functions implemented in Input.js
+
+@interface JSInput : JSModule
+- (void)removePosition:(int)posId;
+
+// UITextInput methods
+- (NSString *)textInRangeStartId:(int)startId startAdjust:(int)startAdjust
+                           endId:(int)endId endAdjust:(int)endAdjust;
+- (void)replaceRangeStart:(int)startId end:(int)endId withText:(NSString *)text;
+- (NSDictionary *)selectedTextRange;
+- (void)setSelectedTextRangeStart:(int)startId end:(int)endId;
+- (NSDictionary *)markedTextRange;
+- (void)setMarkedText:(NSString *)text startOffset:(int)startOffset endOffset:(int)endOffset;
+- (void)unmarkText;
+- (BOOL)forwardSelectionAffinity;
+- (void)setForwardSelectionAffinity:(BOOL)forwardSelectionAffinity;
+- (int)positionFromPosition:(int)posId offset:(int)offset;
+- (int)positionFromPosition:(int)posId inDirection:(NSString *)direction offset:(int)offset;
+- (int)comparePosition:(int)positionId toPosition:(int)otherId;
+- (int)offsetFromPosition:(int)fromPosition toPosition:(int)toPosition;
+- (int)positionWithinRangeStart:(int)startId end:(int)endId farthestInDirection:(NSString *)direction;
+- (NSDictionary *)characterRangeByExtendingPosition:(int)positionId inDirection:(NSString *)direction;
+- (NSDictionary *)firstRectForRangeStart:(int)startId end:(int)endId;
+- (NSDictionary *)caretRectForPosition:(int)posId;
+- (int)closestPositionToPointX:(int)x y:(int)y;
+- (int)closestPositionToPointX:(int)x y:(int)y withinRangeStart:(int)startId end:(int)endId;
+- (NSDictionary *)characterRangeAtPointX:(int)x y:(int)y;
+- (int)positionWithinRangeStart:(int)startId end:(int)endId atCharacterOffset:(int)offset;
+- (int)characterOffsetOfPosition:(int)positionId withinRangeStart:(int)startId end:(int)endId;
+
+// UITextInputTokenizer methods
+- (BOOL)isPosition:(int)posId atBoundary:(NSString *)granularity inDirection:(NSString *)direction;
+- (BOOL)isPosition:(int)posId withinTextUnit:(NSString *)granularity inDirection:(NSString *)direction;
+- (int)positionFromPosition:(int)posId toBoundary:(NSString *)granularity inDirection:(NSString *)direction;
+- (NSDictionary *)rangeEnclosingPosition:(int)posId withGranularity:(NSString *)granularity inDirection:(NSString *)direction;
+@end
+
+// Functions implemented in Lists.js
+
+@interface JSLists : JSModule
+- (void)increaseIndent;
+- (void)decreaseIndent;
+- (void)clearList;
+- (void)setUnorderedList;
+- (void)setOrderedList;
+@end
+
+// Functions implemented in Main.js
+
+@interface JSMain : JSModule
+- (NSString *)getLanguage;
+- (void)setLanguage:(NSString *)language;
+- (NSString *)setGenerator:(NSString *)generator;
+- (BOOL)prepareForSave;
+- (NSString *)getHTML;
+- (BOOL)isEmptyDocument;
+@end
+
+// Functions implemented in Metadata.js
+
+@interface JSMetadata : JSModule
+- (NSDictionary *)getMetadata;
+- (void)setMetadata:(NSDictionary *)metadata;
+@end
+
+// Functions implemented in Outline.js
+
+@interface JSOutline : JSModule
+- (NSDictionary *)getOutline;
+- (void)moveSection:(NSString *)sectionId parentId:(NSString *)parentId nextId:(NSString *)nextId;
+- (void)deleteItem:(NSString *)itemId;
+- (void)goToItem:(NSString *)itemId;
+- (void)scheduleUpdateStructure;
+- (void)set:(NSString *)itemId numbered:(BOOL)numbered;
+- (void)set:(NSString *)itemId title:(NSString *)title;
+- (void)insertTableOfContents;
+- (void)insertListOfFigures;
+- (void)insertListOfTables;
+- (void)setPrintMode:(BOOL)printMode;
+- (NSDictionary *)examinePrintLayout:(int)pageHeight;
+- (BOOL)detectSectionNumbering;
+- (NSDictionary *)findUsedStyles;
+@end
+
+// Functions implemented in Preview.js
+
+@interface JSPreview : JSModule
+- (void)showForStyle:(NSString *)styleId uiName:(NSString *)uiName title:(NSString *)title;
+@end
+
+// Functions implemented in Scan.js
+
+@interface JSScan : JSModule
+- (void)reset;
+- (EDScanParagraph *)next;
+- (int)addMatchStart:(int)start end:(int)end;
+- (void)showMatch:(int)matchId;
+- (void)replaceMatch:(int)matchId with:(NSString *)text;
+- (void)removeMatch:(int)matchId;
+- (void)goToMatch:(int)matchId;
+@end
+
+// Functions implemented in Selection.js
+
+@interface JSSelection : JSModule
+- (void)update;
+- (void)selectAll;
+- (void)selectParagraph;
+- (void)selectWordAtCursor;
+- (NSString *)dragSelectionBeginX:(int)x y:(int)y selectWord:(BOOL)selectWord;
+- (NSString *)dragSelectionUpdateX:(int)x y:(int)y selectWord:(BOOL)selectWord;
+- (NSString *)moveStartLeft;
+- (NSString *)moveStartRight;
+- (NSString *)moveEndLeft;
+- (NSString *)moveEndRight;
+- (void)setSelectionStartAtCoordsX:(int)x y:(int)y;
+- (void)setSelectionEndAtCoordsX:(int)x y:(int)y;
+- (void)setTableSelectionEdge:(NSString *)edge atCoordsX:(int)x y:(int)y;
+- (void)print;
+@end
+
+// Functions implemented in Styles.js
+
+@interface JSStyles : JSModule
+- (NSString *)getCSSText;
+- (void)setCSSText:(NSString *)cssText rules:(NSDictionary *)rules;
+- (NSString *)paragraphClass;
+- (void)setParagraphClass:(NSString *)paragraphClass;
+@end
+
+// Functions implemented in Tables.js
+
+@interface JSTables : JSModule
+- (void)insertTableRows:(int)rows cols:(int)cols width:(NSString *)width numbered:(BOOL)numbered
+                caption:(NSString *)caption className:(NSString *)className;
+- (void)addAdjacentRow;
+- (void)addAdjacentColumn;
+- (void)removeAdjacentRow;
+- (void)removeAdjacentColumn;
+- (void)clearCells;
+- (void)mergeCells;
+- (void)splitSelection;
+- (NSString *)getSelectedTableId;
+- (NSDictionary *)getProperties:(NSString *)itemId;
+- (void)setProperties:(NSString *)itemId width:(NSString *)width;
+- (void)set:(NSString *)itemId colWidths:(NSArray *)colWidths;
+- (NSDictionary *)getGeometry:(NSString *)itemId;
+@end
+
+// Functions implemented in UndoManager.js
+
+@interface JSUndoManager : JSModule
+- (int)getLength;
+- (int)getIndex;
+- (void)setIndex:(int)index;
+- (void)undo;
+- (void)redo;
+- (void)newGroup:(NSString *)name;
+- (NSString *)groupType;
+@end
+
+// Functions implemented in Viewport.js
+
+@interface JSViewport : JSModule
+- (void)setViewportWidth:(int)width;
+- (void)setTextScale:(int)textScale;
+@end
diff --git a/sample/code/objc_bindings/EDJSInterface.m b/sample/code/objc_bindings/EDJSInterface.m
new file mode 100644
index 0000000..51fd1cf
--- /dev/null
+++ b/sample/code/objc_bindings/EDJSInterface.m
@@ -0,0 +1,1788 @@
+// 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.
+
+// IMPORTANT NOTE: This code does not work in it's current form,
+// and exists for illustrative purposes only. It is an excerpt
+// from the UX Write source code indented to show how the bindings
+// between Objective C and JavaScript are implemented, both in
+// terms of calling *in* to JavaScript, and calling *out* of
+// JavaScript (that is, callback functions).
+//
+// The functions are referenced by number, which is due to the
+// fact that prior to the editor code becoming open source, it
+// was obfuscated in the files distributed with UX Write. Thus,
+// each API function was represented as an index into an array
+// of JavaScript functions to be called. This was necessary
+// because the obfuscator I was using (UglifyJS) renamed all the
+// global functions and this was the only way to keep track of them.
+//
+// This numeric referencing of functions is no longer relevant
+// not that there's no need to obfuscate the code (quite the opposite
+// in fact), so when implementing bindings for other languages you
+// can just reference the function names directly.
+
+#import "EDJSInterface.h"
+#import "EDScan.h"
+#import "EDUtil.h"
+#import <FileClient/FCError.h>
+#import <FileClient/FCUtil.h>
+
+typedef enum {
+    AutoCorrect_correctPrecedingWord,
+    AutoCorrect_getCorrection,
+    AutoCorrect_getCorrectionCoords,
+    AutoCorrect_acceptCorrection,
+    AutoCorrect_replaceCorrection,
+    ChangeTracking_showChanges,
+    ChangeTracking_trackChanges,
+    ChangeTracking_setShowChanges,
+    ChangeTracking_setTrackChanges,
+    Clipboard_cut,
+    Clipboard_copy,
+    Clipboard_pasteHTML,
+    Clipboard_pasteText,
+    Cursor_positionCursor,
+    Cursor_getCursorPosition,
+    Cursor_moveLeft,
+    Cursor_moveRight,
+    Cursor_moveToStartOfDocument,
+    Cursor_moveToEndOfDocument,
+    Cursor_insertReference,
+    Cursor_insertLink,
+    Cursor_insertCharacter,
+    Cursor_deleteCharacter,
+    Cursor_enterPressed,
+    Cursor_getPrecedingWord,
+    Cursor_getLinkProperties,
+    Cursor_setLinkProperties,
+    Cursor_setReferenceTarget,
+    Cursor_insertFootnote,
+    Cursor_insertEndnote,
+    Editor_getBackMessages,
+    Equations_insertEquation,
+    Figures_insertFigure,
+    Figures_getSelectedFigureId,
+    Figures_getProperties,
+    Figures_setProperties,
+    Figures_getGeometry,
+    Formatting_getFormatting,
+    Formatting_applyFormattingChanges,
+    Input_removePosition,
+    Input_textInRange,
+    Input_replaceRange,
+    Input_selectedTextRange,
+    Input_setSelectedTextRange,
+    Input_markedTextRange,
+    Input_setMarkedText,
+    Input_unmarkText,
+    Input_forwardSelectionAffinity,
+    Input_setForwardSelectionAffinity,
+    Input_positionFromPositionOffset,
+    Input_positionFromPositionInDirectionOffset,
+    Input_comparePositionToPosition,
+    Input_offsetFromPositionToPosition,
+    Input_positionWithinRangeFarthestInDirection,
+    Input_characterRangeByExtendingPositionInDirection,
+    Input_firstRectForRange,
+    Input_caretRectForPosition,
+    Input_closestPositionToPoint,
+    Input_closestPositionToPointWithinRange,
+    Input_characterRangeAtPoint,
+    Input_positionWithinRangeAtCharacterOffset,
+    Input_characterOffsetOfPositionWithinRange,
+    Input_isPositionAtBoundaryGranularityInDirection,
+    Input_isPositionWithinTextUnitInDirection,
+    Input_positionFromPositionToBoundaryInDirection,
+    Input_rangeEnclosingPositionWithGranularityInDirection,
+    Lists_increaseIndent,
+    Lists_decreaseIndent,
+    Lists_clearList,
+    Lists_setUnorderedList,
+    Lists_setOrderedList,
+    Main_getLanguage,
+    Main_setLanguage,
+    Main_setGenerator,
+    Main_init,
+    Main_getErrorReportingInfo,
+    Main_execute,
+    Main_prepareForSave,
+    Main_getHTML,
+    Main_isEmptyDocument,
+    Metadata_getMetadata,
+    Metadata_setMetadata,
+    Outline_moveSection,
+    Outline_deleteItem,
+    Outline_goToItem,
+    Outline_scheduleUpdateStructure,
+    Outline_setNumbered,
+    Outline_setTitle,
+    Outline_getOutline,
+    Outline_insertTableOfContents,
+    Outline_insertListOfFigures,
+    Outline_insertListOfTables,
+    Outline_setPrintMode,
+    Outline_examinePrintLayout,
+    Outline_detectSectionNumbering,
+    Outline_findUsedStyles,
+    Preview_showForStyle,
+    Scan_reset,
+    Scan_next,
+    Scan_addMatch,
+    Scan_showMatch,
+    Scan_replaceMatch,
+    Scan_removeMatch,
+    Scan_goToMatch,
+    Selection_update,
+    Selection_selectAll,
+    Selection_selectParagraph,
+    Selection_selectWordAtCursor,
+    Selection_dragSelectionBegin,
+    Selection_dragSelectionUpdate,
+    Selection_moveStartLeft,
+    Selection_moveStartRight,
+    Selection_moveEndLeft,
+    Selection_moveEndRight,
+    Selection_setSelectionStartAtCoords,
+    Selection_setSelectionEndAtCoords,
+    Selection_setTableSelectionEdgeAtCoords,
+    Selection_print,
+    Styles_getCSSText,
+    Styles_setCSSText,
+    Styles_getParagraphClass,
+    Styles_setParagraphClass,
+    Tables_insertTable,
+    Tables_addAdjacentRow,
+    Tables_addAdjacentColumn,
+    Tables_removeAdjacentRow,
+    Tables_removeAdjacentColumn,
+    Tables_clearCells,
+    Tables_mergeCells,
+    Tables_splitSelection,
+    Tables_getSelectedTableId,
+    Tables_getProperties,
+    Tables_setProperties,
+    Tables_setColWidths,
+    Tables_getGeometry,
+    UndoManager_getLength,
+    UndoManager_getIndex,
+    UndoManager_setIndex,
+    UndoManager_undo,
+    UndoManager_redo,
+    UndoManager_newGroup,
+    UndoManager_groupType,
+    Viewport_setViewportWidth,
+    Viewport_setTextScale,
+    JSInterfaceFunctionCount,
+} JSInterfaceFunction;
+
+static BOOL functionModifiesDocument(JSInterfaceFunction fun)
+{
+    switch (fun)
+    {
+        case AutoCorrect_correctPrecedingWord:
+        case AutoCorrect_acceptCorrection:
+        case AutoCorrect_replaceCorrection:
+        case ChangeTracking_setShowChanges:
+        case ChangeTracking_setTrackChanges:
+        case Clipboard_cut:
+        case Clipboard_pasteHTML:
+        case Clipboard_pasteText:
+        case Cursor_insertReference:
+        case Cursor_insertLink:
+        case Cursor_insertCharacter:
+        case Cursor_deleteCharacter:
+        case Cursor_enterPressed:
+        case Cursor_setLinkProperties:
+        case Cursor_setReferenceTarget:
+        case Cursor_insertFootnote:
+        case Cursor_insertEndnote:
+        case Equations_insertEquation:
+        case Figures_insertFigure:
+        case Figures_setProperties:
+        case Formatting_applyFormattingChanges:
+        case Lists_increaseIndent:
+        case Lists_decreaseIndent:
+        case Lists_clearList:
+        case Lists_setUnorderedList:
+        case Lists_setOrderedList:
+        case Main_setLanguage:
+        case Main_prepareForSave:
+        case Metadata_setMetadata:
+        case Outline_moveSection:
+        case Outline_deleteItem:
+        case Outline_scheduleUpdateStructure:
+        case Outline_setNumbered:
+        case Outline_setTitle:
+        case Outline_insertTableOfContents:
+        case Outline_insertListOfFigures:
+        case Outline_insertListOfTables:
+        case Outline_setPrintMode:
+        case Outline_examinePrintLayout:
+        case Scan_replaceMatch:
+        case Styles_setCSSText:
+        case Tables_insertTable:
+        case Tables_addAdjacentRow:
+        case Tables_addAdjacentColumn:
+        case Tables_removeAdjacentRow:
+        case Tables_removeAdjacentColumn:
+        case Tables_clearCells:
+        case Tables_mergeCells:
+        case Tables_splitSelection:
+        case Tables_setProperties:
+        case Tables_setColWidths:
+        case UndoManager_undo:
+        case UndoManager_redo:
+            return true;
+        case AutoCorrect_getCorrection:
+        case AutoCorrect_getCorrectionCoords:
+        case ChangeTracking_showChanges:
+        case ChangeTracking_trackChanges:
+        case Clipboard_copy:
+        case Cursor_positionCursor:
+        case Cursor_getCursorPosition:
+        case Cursor_moveLeft:
+        case Cursor_moveRight:
+        case Cursor_moveToStartOfDocument:
+        case Cursor_moveToEndOfDocument:
+        case Cursor_getPrecedingWord:
+        case Cursor_getLinkProperties:
+        case Editor_getBackMessages:
+        case Figures_getSelectedFigureId:
+        case Figures_getProperties:
+        case Figures_getGeometry:
+        case Formatting_getFormatting:
+        case Input_removePosition:
+        case Input_textInRange:
+        case Input_replaceRange:
+        case Input_selectedTextRange:
+        case Input_setSelectedTextRange:
+        case Input_markedTextRange:
+        case Input_setMarkedText:
+        case Input_unmarkText:
+        case Input_forwardSelectionAffinity:
+        case Input_setForwardSelectionAffinity:
+        case Input_positionFromPositionOffset:
+        case Input_positionFromPositionInDirectionOffset:
+        case Input_comparePositionToPosition:
+        case Input_offsetFromPositionToPosition:
+        case Input_positionWithinRangeFarthestInDirection:
+        case Input_characterRangeByExtendingPositionInDirection:
+        case Input_firstRectForRange:
+        case Input_caretRectForPosition:
+        case Input_closestPositionToPoint:
+        case Input_closestPositionToPointWithinRange:
+        case Input_characterRangeAtPoint:
+        case Input_positionWithinRangeAtCharacterOffset:
+        case Input_characterOffsetOfPositionWithinRange:
+        case Input_isPositionAtBoundaryGranularityInDirection:
+        case Input_isPositionWithinTextUnitInDirection:
+        case Input_positionFromPositionToBoundaryInDirection:
+        case Input_rangeEnclosingPositionWithGranularityInDirection:
+        case Main_getLanguage:
+        case Main_setGenerator:
+        case Main_init:
+        case Main_getErrorReportingInfo:
+        case Main_execute:
+        case Main_getHTML:
+        case Main_isEmptyDocument:
+        case Metadata_getMetadata:
+        case Outline_getOutline:
+        case Outline_goToItem:
+        case Outline_detectSectionNumbering:
+        case Outline_findUsedStyles:
+        case Preview_showForStyle:
+        case Scan_reset:
+        case Scan_next:
+        case Scan_addMatch:
+        case Scan_showMatch:
+        case Scan_removeMatch:
+        case Scan_goToMatch:
+        case Selection_update:
+        case Selection_selectAll:
+        case Selection_selectParagraph:
+        case Selection_selectWordAtCursor:
+        case Selection_dragSelectionBegin:
+        case Selection_dragSelectionUpdate:
+        case Selection_moveStartLeft:
+        case Selection_moveStartRight:
+        case Selection_moveEndLeft:
+        case Selection_moveEndRight:
+        case Selection_setSelectionStartAtCoords:
+        case Selection_setSelectionEndAtCoords:
+        case Selection_setTableSelectionEdgeAtCoords:
+        case Selection_print:
+        case Styles_getCSSText:
+        case Styles_getParagraphClass:
+        case Styles_setParagraphClass:
+        case Tables_getSelectedTableId:
+        case Tables_getProperties:
+        case Tables_getGeometry:
+        case UndoManager_getLength:
+        case UndoManager_getIndex:
+        case UndoManager_setIndex:
+        case UndoManager_newGroup:
+        case UndoManager_groupType:
+        case Viewport_setViewportWidth:
+        case Viewport_setTextScale:
+        case JSInterfaceFunctionCount:
+            return false;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                             JSError                                            //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSError
+
+- (JSError *)initWithType:(NSString *)type
+                  message:(NSString *)message
+                operation:(NSString *)operation
+                     html:(NSString *)html
+{
+    if (!(self = [super init]))
+        return nil;
+    _type = [type copy];
+    _message = [message copy];
+    _operation = [operation copy];
+    _html = [html copy];
+    return self;
+}
+
+- (NSString *)description
+{
+    NSMutableString *errorInfo = [NSMutableString stringWithCapacity: 0];
+    [errorInfo appendFormat: @"%@\n", _message];
+    [errorInfo appendFormat: @"Operation: %@\n", _operation];
+    [errorInfo appendFormat: @"\n"];
+    [errorInfo appendFormat: @"HTML:\n%@\n", _html];
+    return errorInfo;
+}
+
+- (NSString *)localizedDescription
+{
+    return [self description];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                           JSInterface                                          //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSInterface
+{
+    NSUInteger _numCalls[JSInterfaceFunctionCount];
+    NSTimeInterval _timeUsed[JSInterfaceFunctionCount];
+    NSTimeInterval _totalTimeUsed;
+}
+
+- (JSInterface *)initWithEvaluator:(NSObject<JSEvaluator> *)evaluator
+{
+    if (!(self = [super init]))
+        return nil;
+    _evaluator = evaluator;
+
+    _autoCorrect = [[JSAutoCorrect alloc] initWithJS: self];
+    _changeTracking = [[JSChangeTracking alloc] initWithJS: self];
+    _clipboard = [[JSClipboard alloc] initWithJS: self];
+    _cursor = [[JSCursor alloc] initWithJS: self];
+    _equations = [[JSEquations alloc] initWithJS: self];
+    _figures = [[JSFigures alloc] initWithJS: self];
+    _formatting = [[JSFormatting alloc] initWithJS: self];
+    _input = [[JSInput alloc] initWithJS: self];
+    _lists = [[JSLists alloc] initWithJS: self];
+    _main = [[JSMain alloc] initWithJS: self];
+    _metadata = [[JSMetadata alloc] initWithJS: self];
+    _outline = [[JSOutline alloc] initWithJS: self];
+    _preview = [[JSPreview alloc] initWithJS: self];
+    _scan = [[JSScan alloc] initWithJS: self];
+    _selection = [[JSSelection alloc] initWithJS: self];
+    _styles = [[JSStyles alloc] initWithJS: self];
+    _tables = [[JSTables alloc] initWithJS: self];
+    _undoManager = [[JSUndoManager alloc] initWithJS: self];
+    _viewport = [[JSViewport alloc] initWithJS: self];
+
+    return self;
+}
+
+- (void)dealloc
+{
+    _autoCorrect.js = nil;
+    _changeTracking.js = nil;
+    _clipboard.js = nil;
+    _cursor.js = nil;
+    _equations.js = nil;
+    _figures.js = nil;
+    _formatting.js = nil;
+    _input.js = nil;
+    _lists.js = nil;
+    _main.js = nil;
+    _metadata.js = nil;
+    _outline.js = nil;
+    _preview.js = nil;
+    _scan.js = nil;
+    _selection.js = nil;
+    _styles.js = nil;
+    _tables.js = nil;
+    _undoManager.js = nil;
+    _viewport.js = nil;
+}
+
+- (BOOL)initJavaScriptWidth:(int)width textScale:(int)textScale cssURL:(NSString *)cssURL
+             clientRectsBug:(BOOL)clientRectsBug
+{
+    // Special case javascript call to Main_init(). We don't use the normal mechanism here because
+    // at this point the JS interface has not been initialised, and the check for this in
+    // executeJavaScriptWithJSONResult would cause it to fail.
+    NSString *code = [NSString stringWithFormat: @"interface_functions[%d](%d,%d,\"%@\",%@)",
+                      Main_init, width, textScale, cssURL, clientRectsBug ? @"true" : @"false"];
+    NSString *result = [_evaluator stringByEvaluatingJavaScriptFromString: code];
+    [self jsCallCompleted];
+    if ([@"true" isEqualToString: result]) {
+        return YES;
+    }
+    else {
+        self.currentOperation = @"JavaScript initialisation";
+        [self reportErrorWithType: nil format: @"%@", result];
+        self.currentOperation = nil;
+        return NO;
+    }
+}
+
+- (void)jsCallCompleted
+{
+    // Process pending callbacks
+    NSString *getBackMessages = [NSString stringWithFormat: @"interface_functions[%d]()",
+                                 Editor_getBackMessages];
+    NSString *str = [_evaluator stringByEvaluatingJavaScriptFromString: getBackMessages];
+    NSData *data = [str dataUsingEncoding: NSUTF8StringEncoding];
+    NSArray *array = [NSJSONSerialization JSONObjectWithData: data options: 0 error: nil];
+    for (NSArray *message in array)
+        [self dispatchCallbackMessage: message];
+}
+
+- (NSString *)operationStringWithFunction:(JSInterfaceFunction)function nargs:(int)nargs arguments:(va_list)ap
+{
+    NSMutableString *operation = [NSMutableString stringWithCapacity: 0];
+    [operation appendFormat: @"interface_functions[%d](", function];
+    NSObject *arg;
+    for (int argno = 0; argno < nargs; argno++) {
+        arg = va_arg(ap,NSObject*);
+        if (argno > 0)
+            [operation appendString: @","];
+        if (arg == nil) {
+            [operation appendString: @"null"];
+        }
+        else if ([arg isKindOfClass: [NSNumber class]]) {
+            [operation appendString: [arg description]];
+        }
+        else if ([arg isKindOfClass: [NSNull class]]) {
+            [operation appendString: @"null"];
+        }
+        else if ([arg isKindOfClass: [NSArray class]] || [arg isKindOfClass: [NSDictionary class]]) {
+            NSError *err = nil;
+            NSData *data = [NSJSONSerialization dataWithJSONObject: arg options: 0 error: &err];
+            if (data == nil) {
+                [NSException raise: @"NSJSONSerialization"
+                            format: @"executeJavaScript %d: cannot serialise argument %d to JSON: %@",
+                                    function, argno, FCErrorDescription(err)];
+            }
+            else {
+                NSString *str = [[NSString alloc] initWithBytes: data.bytes length: data.length
+                                                       encoding: NSUTF8StringEncoding];
+                [operation appendString: str];
+            }
+        }
+        else {
+            char *quoted = DFQuote(arg.description.UTF8String);
+            NSString *nsQuoted = [NSString stringWithUTF8String: quoted];
+            [operation appendString: nsQuoted];
+            free(quoted);
+        }
+    }
+    [operation appendString: @")"];
+    return operation;
+}
+
+- (id)executeJavaScriptWithJSONResult:(BOOL)jsonResult function:(JSInterfaceFunction)function nargs:(int)nargs arguments:(va_list)ap
+{
+    NSDate *start = [NSDate date];
+    if (!_jsInitialised) {
+        [NSException raise: @"JavaScriptNotInitialised"
+                    format: @"Yet to receive a jsInterfaceInitFinished from JavaScript code"];
+    }
+    self.currentOperation = [self operationStringWithFunction: function nargs: nargs arguments: ap];
+    id result;
+    if (!jsonResult) {
+        NSString *code = [NSString stringWithFormat: @"interface_functions[%d](function() { return %@; });",
+                                                     Main_execute, self.currentOperation];
+        result = [_evaluator stringByEvaluatingJavaScriptFromString: code];
+        [self jsCallCompleted];
+    }
+    else {
+        NSString *code = [NSString stringWithFormat: @"interface_functions[%d](function() { return JSON.stringify(%@); });",
+                                                     Main_execute, self.currentOperation];
+
+        NSString *str = [_evaluator stringByEvaluatingJavaScriptFromString: code];
+        [self jsCallCompleted];
+
+        if ([str isEqualToString: @"null"]) {
+            result = nil;
+        }
+        else {
+            NSData *data = [str dataUsingEncoding: NSUTF8StringEncoding];
+            NSError *err = nil;
+            result = [NSJSONSerialization JSONObjectWithData: data options: 0 error: &err];
+            if (result == nil) {
+                [self reportErrorWithType: nil format: @"Cannot deserialise JSON result \"%@\": %@",
+                 str, FCErrorDescription(err)];
+            }
+        }
+    }
+
+    NSDate *end = [NSDate date];
+    NSTimeInterval interval = [end timeIntervalSinceDate: start];
+    _numCalls[function]++;
+    _timeUsed[function] += interval;
+    _totalTimeUsed += interval;
+
+    self.currentOperation = nil;
+    if (functionModifiesDocument(function))
+        self.documentModified = YES;
+    return result;
+}
+
+- (void)printStatistics
+{
+    if (_totalTimeUsed == 0.0)
+        return;
+
+    printf("\n");
+    printf("%-10s %-10s %-10s %-10s\n","Function","Calls","Time","Time pct");
+
+    NSMutableArray *order = [NSMutableArray arrayWithCapacity: 0];
+    for (NSUInteger i = 0; i < JSInterfaceFunctionCount; i++)
+        [order addObject: [NSNumber numberWithUnsignedInteger: i]];
+    [order sortUsingComparator:^NSComparisonResult(NSNumber *n1, NSNumber *n2) {
+        NSUInteger i1 = n1.unsignedIntValue;
+        NSUInteger i2 = n2.unsignedIntValue;
+        if (_timeUsed[i1] < _timeUsed[i2])
+            return NSOrderedAscending;
+        else if (_timeUsed[i1] > _timeUsed[i2])
+            return NSOrderedDescending;
+        else
+            return NSOrderedSame;
+    }];
+    for (NSNumber *n in order) {
+        NSUInteger i = n.unsignedIntValue;
+        double pct = 100*(_timeUsed[i]/_totalTimeUsed);
+        if (pct >= 0.01) {
+            printf("%-10d %-10d %-10d %.2f%%\n",(int)i,(int)_numCalls[i],(int)(_timeUsed[i]*1000),pct);
+        }
+    }
+    printf("totalTimeUsed = %.2fms\n",1000*_totalTimeUsed);
+}
+
+- (id)executeJavaScriptJSON:(JSInterfaceFunction)function nargs:(int)nargs, ...
+{
+    va_list ap;
+    va_start(ap,nargs);
+    NSString *result = (NSString *)[self executeJavaScriptWithJSONResult: YES
+                                                                function: function
+                                                                   nargs: nargs
+                                                               arguments: ap];
+    va_end(ap);
+    return result;
+}
+
+- (NSString *)executeJavaScript:(JSInterfaceFunction)function nargs:(int)nargs, ...
+{
+    va_list ap;
+    va_start(ap,nargs);
+    NSString *result = (NSString *)[self executeJavaScriptWithJSONResult: NO
+                                                                function: function
+                                                                   nargs: nargs
+                                                               arguments: ap];
+    va_end(ap);
+    return result;
+}
+
+- (void)dispatchCallbackMessage:(NSArray*)array
+{
+    if (array.count == 0)
+        return;
+
+    if (![[array objectAtIndex: 0] isKindOfClass: [NSString class]])
+        return;
+
+    NSString *functionName = [array objectAtIndex: 0];
+
+    if ([functionName isEqualToString: @"debug"] &&
+        ([array count] == 2) &&
+        [[array objectAtIndex: 1] isKindOfClass: [NSString class]]) {
+        NSString *message = [array objectAtIndex: 1];
+        debug(@"%@\n",message);
+    }
+    else if ([functionName isEqualToString: @"addOutlineItem"] &&
+             [_delegate respondsToSelector: @selector(jsAddOutlineItem:type:title:)] &&
+             ([array count] == 4) &&
+             [[array objectAtIndex: 1] isKindOfClass: [NSString class]] &&
+             [[array objectAtIndex: 2] isKindOfClass: [NSString class]]) {
+        // 3 could be a a string or null
+        NSString *title = [array objectAtIndex: 3];
+        if ([title isKindOfClass: [NSNull class]])
+            title = nil;
+        [_delegate jsAddOutlineItem: [array objectAtIndex: 1]
+                              type: [array objectAtIndex: 2]
+                             title: title];
+    }
+    else if ([functionName isEqualToString: @"updateOutlineItem"] &&
+             [_delegate respondsToSelector: @selector(jsUpdateOutlineItem:title:)] &&
+             ([array count] == 3) &&
+             [[array objectAtIndex: 1] isKindOfClass: [NSString class]] &&
+             [[array objectAtIndex: 2] isKindOfClass: [NSString class]]) {
+        [_delegate jsUpdateOutlineItem: [array objectAtIndex: 1] title: [array objectAtIndex: 2]];
+    }
+    else if ([functionName isEqualToString: @"removeOutlineItem"] &&
+             [_delegate respondsToSelector: @selector(jsRemoveOutlineItem:)] &&
+             ([array count] == 2) &&
+             [[array objectAtIndex: 1] isKindOfClass: [NSString class]]) {
+        [_delegate jsRemoveOutlineItem: [array objectAtIndex: 1]];
+    }
+    else if ([functionName isEqualToString: @"outlineUpdated"] &&
+             [_delegate respondsToSelector: @selector(jsOutlineUpdated)] &&
+             [array count] == 1) {
+        [_delegate jsOutlineUpdated];
+    }
+    else if ([functionName isEqualToString: @"setSelectionHandles"] &&
+             [_delegate respondsToSelector: @selector(jsSetSelectionHandlesX1:y1:height1:x2:y2:height2:)] &&
+             ([array count] == 7) &&
+             ([[array objectAtIndex: 1] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 2] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 3] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 4] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 5] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 6] isKindOfClass: [NSNumber class]])) {
+        [_delegate jsSetSelectionHandlesX1: ((NSNumber *)[array objectAtIndex: 1]).intValue
+                                       y1: ((NSNumber *)[array objectAtIndex: 2]).intValue
+                                  height1: ((NSNumber *)[array objectAtIndex: 3]).intValue
+                                       x2: ((NSNumber *)[array objectAtIndex: 4]).intValue
+                                       y2: ((NSNumber *)[array objectAtIndex: 5]).intValue
+                                  height2: ((NSNumber *)[array objectAtIndex: 6]).intValue];
+    }
+    else if ([functionName isEqualToString: @"setTableSelection"] &&
+             [_delegate respondsToSelector: @selector(jsSetTableSelectionX:y:width:height:)] &&
+             ([array count] == 5) &&
+             ([[array objectAtIndex: 1] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 2] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 3] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 4] isKindOfClass: [NSNumber class]])) {
+        [_delegate jsSetTableSelectionX: ((NSNumber *)[array objectAtIndex: 1]).intValue
+                                     y: ((NSNumber *)[array objectAtIndex: 2]).intValue
+                                 width: ((NSNumber *)[array objectAtIndex: 3]).intValue
+                                height: ((NSNumber *)[array objectAtIndex: 4]).intValue];
+    }
+    else if ([functionName isEqualToString: @"setCursor"] &&
+             [_delegate respondsToSelector: @selector(jsSetCursorX:y:width:height:)] &&
+             ([array count] == 5) &&
+             ([[array objectAtIndex: 1] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 2] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 3] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 4] isKindOfClass: [NSNumber class]])) {
+        [_delegate jsSetCursorX: ((NSNumber *)[array objectAtIndex: 1]).intValue
+                             y: ((NSNumber *)[array objectAtIndex: 2]).intValue
+                         width: ((NSNumber *)[array objectAtIndex: 3]).intValue
+                        height: ((NSNumber *)[array objectAtIndex: 4]).intValue];
+    }
+    else if ([functionName isEqualToString: @"clearSelectionHandlesAndCursor"] &&
+             [_delegate respondsToSelector: @selector(jsClearSelectionHandlesAndCursor)] &&
+             ([array count] == 1)) {
+        [_delegate jsClearSelectionHandlesAndCursor];
+    }
+    else if ([functionName isEqualToString: @"setSelectionBounds"] &&
+             [_delegate respondsToSelector: @selector(jsSetSelectionBoundsLeft:top:right:bottom:)] &&
+             ([array count] == 5) &&
+             ([[array objectAtIndex: 1] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 2] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 3] isKindOfClass: [NSNumber class]]) &&
+             ([[array objectAtIndex: 4] isKindOfClass: [NSNumber class]])) {
+        [_delegate jsSetSelectionBoundsLeft: ((NSNumber *)[array objectAtIndex: 1]).intValue
+                                       top: ((NSNumber *)[array objectAtIndex: 2]).intValue
+                                     right: ((NSNumber *)[array objectAtIndex: 3]).intValue
+                                    bottom: ((NSNumber *)[array objectAtIndex: 4]).intValue];
+    }
+    else if ([functionName isEqualToString: @"updateAutoCorrect"] &&
+             [_delegate respondsToSelector: @selector(jsUpdateAutoCorrect)]) {
+        [_delegate jsUpdateAutoCorrect];
+    }
+    else if ([functionName isEqualToString: @"error"] &&
+             (array.count == 3) &&
+             [[array objectAtIndex: 1] isKindOfClass: [NSString class]] &&
+             [[array objectAtIndex: 2] isKindOfClass: [NSString class]]) {
+        NSString *message = [array objectAtIndex: 1];
+        NSString *type = [array objectAtIndex: 2];
+        if (type.length == 0)
+            type = nil;
+        [self reportErrorWithType: type format: @"%@", message];
+    }
+}
+
+- (void)reportErrorWithType:(NSString *)type format:(NSString *)format, ...
+{
+    if (self.error != nil)
+        return;
+
+    va_list ap;
+    va_start(ap,format);
+    NSString *basicError = [[NSString alloc] initWithFormat: format arguments: ap];
+    va_end(ap);
+
+    NSString *getErrorReportingInfo = [NSString stringWithFormat: @"interface_functions[%d]()",
+                                       Main_getErrorReportingInfo];
+    NSString *html = [_evaluator stringByEvaluatingJavaScriptFromString: getErrorReportingInfo];
+
+    self.error = [[JSError alloc] initWithType: type
+                                       message: basicError
+                                     operation: self.currentOperation
+                                          html: html];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                            JSModule                                            //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSModule
+
+- (JSModule *)initWithJS:(JSInterface *)js
+{
+    if (!(self = [super init]))
+        return nil;
+    _js = js;
+    return self;
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                          JSAutoCorrect                                         //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSAutoCorrect
+
+- (void)correctPreceding:(int)numChars word:(NSString *)replacement confirmed:(BOOL)confirmed;
+{
+    [self.js executeJavaScript: AutoCorrect_correctPrecedingWord nargs: 3,
+     [NSNumber numberWithInt: numChars], replacement, [NSNumber numberWithBool: confirmed]];
+}
+
+- (NSDictionary *)getCorrection
+{
+    return [self.js executeJavaScriptJSON: AutoCorrect_getCorrection nargs: 0];
+}
+
+- (NSDictionary *)getCorrectionCoords
+{
+    return [self.js executeJavaScriptJSON: AutoCorrect_getCorrectionCoords nargs: 0];
+}
+
+- (void)acceptCorrection
+{
+    [self.js executeJavaScript: AutoCorrect_acceptCorrection nargs: 0];
+}
+
+- (void)replaceCorrection:(NSString *)replacement
+{
+    [self.js executeJavaScript: AutoCorrect_replaceCorrection nargs: 1, replacement];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                        JSChangeTracking                                        //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSChangeTracking
+
+- (BOOL)showChanges
+{
+    NSString *result = [self.js executeJavaScript: ChangeTracking_showChanges nargs: 0];
+    return [result isEqualToString: @"true"];
+}
+
+- (BOOL)trackChanges
+{
+    NSString *result = [self.js executeJavaScript: ChangeTracking_trackChanges nargs: 0];
+    return [result isEqualToString: @"true"];
+}
+
+- (void)setShowChanges:(BOOL)showChanges
+{
+    [self.js executeJavaScript: ChangeTracking_setShowChanges
+                         nargs: 1, [NSNumber numberWithBool: showChanges]];
+}
+
+- (void)setTrackChanges:(BOOL)trackChanges
+{
+    [self.js executeJavaScript: ChangeTracking_setTrackChanges
+                         nargs: 1, [NSNumber numberWithBool: trackChanges]];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                           JSClipboard                                          //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSClipboard
+
+// The copy operation is called clipboardCopy to keep the static analyzer happy, because it thinks
+// that it relates to making a copy of the object and reports a memory leak. The cut operation
+// is named similarly just for consistency.
+
+- (NSDictionary *)clipboardCut
+{
+    return [self.js executeJavaScriptJSON: Clipboard_cut nargs: 0];
+}
+
+- (NSDictionary *)clipboardCopy
+{
+    return [self.js executeJavaScriptJSON: Clipboard_copy nargs: 0];
+}
+
+- (void)pasteHTML:(NSString *)html
+{
+    [self.js executeJavaScript: Clipboard_pasteHTML nargs: 1, html];
+}
+
+- (void)pasteText:(NSString *)text
+{
+    [self.js executeJavaScript: Clipboard_pasteText nargs: 1, text];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                            JSCursor                                            //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Functions implemented in Cursor.js
+
+@implementation JSCursor
+
+- (NSString *)positionCursorX:(int)x y:(int)y wordBoundary:(BOOL)wordBoundary
+{
+    return [self.js executeJavaScript: Cursor_positionCursor nargs: 3,
+            [NSNumber numberWithInt: x], [NSNumber numberWithInt: y],
+            [NSNumber numberWithBool: wordBoundary]];
+}
+
+- (CGRect)getCursorPosition
+{
+    NSDictionary *result = [self.js executeJavaScriptJSON: Cursor_getCursorPosition nargs: 0];
+    return CGRectMake(NSDictionaryGetInt(result,@"x"),
+                      NSDictionaryGetInt(result,@"y"),
+                      NSDictionaryGetInt(result,@"width"),
+                      NSDictionaryGetInt(result,@"height"));
+}
+
+- (void)moveLeft
+{
+    [self.js executeJavaScript: Cursor_moveLeft nargs: 0];
+}
+
+- (void)moveRight
+{
+    [self.js executeJavaScript: Cursor_moveRight nargs: 0];
+}
+
+- (void)moveToStartOfDocument
+{
+    [self.js executeJavaScript: Cursor_moveToStartOfDocument nargs: 0];
+}
+
+- (void)moveToEndOfDocument
+{
+    [self.js executeJavaScript: Cursor_moveToEndOfDocument nargs: 0];
+}
+
+- (void)insertReference:(NSString *)itemId
+{
+    [self.js executeJavaScript: Cursor_insertReference nargs: 1, itemId];
+}
+
+- (void)insertLinkWithText:(NSString *)text URL:(NSString *)URL
+{
+    [self.js executeJavaScript: Cursor_insertLink nargs: 2, text, URL];
+}
+
+- (void)insertCharacter:(unichar)character allowInvalidPos:(BOOL)allowInvalidPos
+{
+    NSString *str = [NSString stringWithFormat: @"%C", character];
+    [self.js executeJavaScript: Cursor_insertCharacter nargs: 2, str,
+     [NSNumber numberWithBool: allowInvalidPos]];
+}
+
+- (void)deleteCharacter
+{
+    [self.js executeJavaScript: Cursor_deleteCharacter nargs: 0];
+}
+
+- (void)enterPressed
+{
+    [self.js executeJavaScript: Cursor_enterPressed nargs: 0];
+}
+
+- (NSString *)getPrecedingWord
+{
+    return [self.js executeJavaScript: Cursor_getPrecedingWord nargs: 0];
+}
+
+- (NSDictionary *)getLinkProperties
+{
+    return [self.js executeJavaScriptJSON: Cursor_getLinkProperties nargs: 0];
+}
+
+- (void)setLinkProperties:(NSDictionary *)properties
+{
+    [self.js executeJavaScript: Cursor_setLinkProperties nargs: 1, properties];
+}
+
+- (void)setReferenceTarget:(NSString *)itemId
+{
+    [self.js executeJavaScript: Cursor_setReferenceTarget nargs: 1, itemId];
+}
+
+- (void)insertFootnote:(NSString *)content
+{
+    [self.js executeJavaScript: Cursor_insertFootnote nargs: 1, content];
+}
+
+- (void)insertEndnote:(NSString *)content
+{
+    [self.js executeJavaScript: Cursor_insertEndnote nargs: 1, content];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                            Equations                                           //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSEquations
+
+- (void)insertEquation
+{
+    [self.js executeJavaScript: Equations_insertEquation nargs: 0];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                            JSFigures                                           //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSFigures
+
+- (void)insertFigure:(NSString *)filename width:(NSString *)width
+            numbered:(BOOL)numbered caption:(NSString *)caption
+{
+    [self.js executeJavaScript: Figures_insertFigure nargs: 4,
+     filename, width, [NSNumber numberWithBool: numbered], caption];
+}
+
+- (NSString *)getSelectedFigureId
+{
+    return [self.js executeJavaScript: Figures_getSelectedFigureId nargs: 0];
+}
+
+- (NSDictionary *)getProperties:(NSString *)itemId
+{
+    return [self.js executeJavaScriptJSON: Figures_getProperties nargs: 1, itemId];
+}
+
+- (void)setProperties:(NSString *)itemId width:(NSString *)width src:(NSString *)src
+{
+    [self.js executeJavaScript: Figures_setProperties nargs: 3, itemId, width, src];
+}
+
+- (NSDictionary *)getGeometry:(NSString *)itemId
+{
+    return [self.js executeJavaScriptJSON: Figures_getGeometry nargs: 1, itemId];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                          JSFormatting                                          //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Functions implemented in Formatting.js
+
+@implementation JSFormatting
+
+- (NSDictionary *)getFormatting
+{
+    return [self.js executeJavaScriptJSON: Formatting_getFormatting nargs: 0];
+}
+
+- (void)applyFormattingChangesStyle:(NSString *)style properties:(NSDictionary *)properties
+{
+    [self.js executeJavaScript: Formatting_applyFormattingChanges nargs: 2, style, properties];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                             JSInput                                            //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSInput
+
+- (void)removePosition:(int)posId
+{
+    [self.js executeJavaScript: Input_removePosition nargs: 1, [NSNumber numberWithInt: posId]];
+}
+
+- (NSString *)textInRangeStartId:(int)startId startAdjust:(int)startAdjust
+                           endId:(int)endId endAdjust:(int)endAdjust
+{
+    return [self.js executeJavaScript: Input_textInRange nargs: 4,
+            [NSNumber numberWithInt: startId],
+            [NSNumber numberWithInt: startAdjust],
+            [NSNumber numberWithInt: endId],
+            [NSNumber numberWithInt: endAdjust]];
+}
+
+- (void)replaceRangeStart:(int)startId end:(int)endId withText:(NSString *)text
+{
+    [self.js executeJavaScript: Input_replaceRange nargs: 3,
+     [NSNumber numberWithInt: startId], [NSNumber numberWithInt: endId], text];
+}
+
+- (NSDictionary *)selectedTextRange
+{
+    return [self.js executeJavaScriptJSON: Input_selectedTextRange nargs: 0];
+}
+
+- (void)setSelectedTextRangeStart:(int)startId end:(int)endId
+{
+    [self.js executeJavaScript: Input_setSelectedTextRange nargs: 2,
+     [NSNumber numberWithInt: startId], [NSNumber numberWithInt: endId]];
+}
+
+- (NSDictionary *)markedTextRange
+{
+    return [self.js executeJavaScriptJSON: Input_markedTextRange nargs: 0];
+}
+
+- (void)setMarkedText:(NSString *)text startOffset:(int)startOffset endOffset:(int)endOffset
+{
+    [self.js executeJavaScript: Input_setMarkedText nargs: 3,
+     text, [NSNumber numberWithInt: startOffset], [NSNumber numberWithInt: endOffset]];
+}
+
+- (void)unmarkText
+{
+    [self.js executeJavaScript: Input_unmarkText nargs: 0];
+}
+
+- (BOOL)forwardSelectionAffinity
+{
+    NSString *result = [self.js executeJavaScript: Input_forwardSelectionAffinity nargs: 0];
+    return [result isEqualToString: @"true"];
+}
+
+- (void)setForwardSelectionAffinity:(BOOL)forwardSelectionAffinity
+{
+    [self.js executeJavaScript: Input_setForwardSelectionAffinity nargs: 1,
+     [NSNumber numberWithBool: forwardSelectionAffinity]];
+}
+
+- (int)positionFromPosition:(int)posId offset:(int)offset
+{
+    NSString *result = [self.js executeJavaScript: Input_positionFromPositionOffset nargs: 2,
+                        [NSNumber numberWithInt: posId], [NSNumber numberWithInt: offset]];
+    return result.intValue;
+}
+
+- (int)positionFromPosition:(int)posId inDirection:(NSString *)direction offset:(int)offset
+{
+    NSString *result = [self.js executeJavaScript: Input_positionFromPositionInDirectionOffset nargs: 3,
+                        [NSNumber numberWithInt: posId], direction, [NSNumber numberWithInt: offset]];
+    return result.intValue;
+}
+
+- (int)comparePosition:(int)positionId toPosition:(int)otherId
+{
+    NSString *result = [self.js executeJavaScript: Input_comparePositionToPosition nargs: 2,
+                        [NSNumber numberWithInt: positionId], [NSNumber numberWithInt: otherId]];
+    return result.intValue;
+}
+
+- (int)offsetFromPosition:(int)fromPosition toPosition:(int)toPosition
+{
+    NSString *result = [self.js executeJavaScript: Input_offsetFromPositionToPosition nargs: 2,
+                        [NSNumber numberWithInt: fromPosition], [NSNumber numberWithInt: toPosition]];
+    return result.intValue;
+}
+
+- (int)positionWithinRangeStart:(int)startId end:(int)endId farthestInDirection:(NSString *)direction
+{
+    NSString *result = [self.js executeJavaScript: Input_positionWithinRangeFarthestInDirection nargs: 3,
+                        [NSNumber numberWithInt: startId], [NSNumber numberWithInt: endId], direction];
+    return result.intValue;
+}
+
+- (NSDictionary *)characterRangeByExtendingPosition:(int)positionId inDirection:(NSString *)direction
+{
+    return [self.js executeJavaScriptJSON: Input_characterRangeByExtendingPositionInDirection nargs: 2,
+            [NSNumber numberWithInt: positionId], direction];
+}
+
+- (NSDictionary *)firstRectForRangeStart:(int)startId end:(int)endId
+{
+    return [self.js executeJavaScriptJSON: Input_firstRectForRange nargs: 2,
+            [NSNumber numberWithInt: startId], [NSNumber numberWithInt: endId]];
+}
+
+- (NSDictionary *)caretRectForPosition:(int)posId
+{
+    return [self.js executeJavaScriptJSON: Input_caretRectForPosition nargs: 1,
+            [NSNumber numberWithInt: posId]];
+}
+
+- (int)closestPositionToPointX:(int)x y:(int)y
+{
+    NSString *result = [self.js executeJavaScript: Input_closestPositionToPoint nargs: 2,
+                        [NSNumber numberWithInt: x], [NSNumber numberWithInt: y]];
+    return result.intValue;
+}
+
+- (int)closestPositionToPointX:(int)x y:(int)y withinRangeStart:(int)startId end:(int)endId
+{
+    NSString *result = [self.js executeJavaScript: Input_closestPositionToPointWithinRange nargs: 4,
+                        [NSNumber numberWithInt: x], [NSNumber numberWithInt: y],
+                        [NSNumber numberWithInt: startId], [NSNumber numberWithInt: endId]];
+    return result.intValue;
+}
+
+- (NSDictionary *)characterRangeAtPointX:(int)x y:(int)y
+{
+    return [self.js executeJavaScriptJSON: Input_characterRangeAtPoint nargs: 2,
+            [NSNumber numberWithInt: x], [NSNumber numberWithInt: y]];
+}
+
+- (int)positionWithinRangeStart:(int)startId end:(int)endId atCharacterOffset:(int)offset
+{
+    NSString *result = [self.js executeJavaScript: Input_positionWithinRangeAtCharacterOffset nargs: 3,
+                        [NSNumber numberWithInt: startId], [NSNumber numberWithInt: endId],
+                        [NSNumber numberWithInt: offset]];
+    return result.intValue;
+}
+
+- (int)characterOffsetOfPosition:(int)positionId withinRangeStart:(int)startId end:(int)endId
+{
+    NSString *result = [self.js executeJavaScript: Input_characterOffsetOfPositionWithinRange nargs: 3,
+                        [NSNumber numberWithInt: positionId],
+                        [NSNumber numberWithInt: startId], [NSNumber numberWithInt: endId]];
+    return result.intValue;
+}
+
+// UITextInputTokenizer methods
+
+- (BOOL)isPosition:(int)posId atBoundary:(NSString *)granularity inDirection:(NSString *)direction
+{
+    NSString *result = [self.js executeJavaScript: Input_isPositionAtBoundaryGranularityInDirection nargs: 3,
+                        [NSNumber numberWithInt: posId], granularity, direction];
+    return [result isEqualToString: @"true"];
+}
+
+- (BOOL)isPosition:(int)posId withinTextUnit:(NSString *)granularity inDirection:(NSString *)direction
+{
+    NSString *result = [self.js executeJavaScript: Input_isPositionWithinTextUnitInDirection nargs: 3,
+                        [NSNumber numberWithInt: posId], granularity, direction];
+    return [result isEqualToString: @"true"];
+}
+
+- (int)positionFromPosition:(int)posId toBoundary:(NSString *)granularity inDirection:(NSString *)direction
+{
+    NSString *result = [self.js executeJavaScript: Input_positionFromPositionToBoundaryInDirection nargs: 3,
+                        [NSNumber numberWithInt: posId], granularity, direction];
+    return result.intValue;
+}
+
+- (NSDictionary *)rangeEnclosingPosition:(int)posId withGranularity:(NSString *)granularity inDirection:(NSString *)direction
+{
+    return [self.js executeJavaScriptJSON: Input_rangeEnclosingPositionWithGranularityInDirection nargs: 3,
+            [NSNumber numberWithInt: posId], granularity, direction];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                             JSLists                                            //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Functions implemented in Lists.js
+
+@implementation JSLists
+
+- (void)increaseIndent
+{
+    [self.js executeJavaScript: Lists_increaseIndent nargs: 0];
+}
+
+- (void)decreaseIndent
+{
+    [self.js executeJavaScript: Lists_decreaseIndent nargs: 0];
+}
+
+- (void)clearList
+{
+    [self.js executeJavaScript: Lists_clearList nargs: 0];
+}
+
+- (void)setUnorderedList
+{
+    [self.js executeJavaScript: Lists_setUnorderedList nargs: 0];
+}
+
+- (void)setOrderedList
+{
+    [self.js executeJavaScript: Lists_setOrderedList nargs: 0];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                             JSMain                                             //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Functions implemented in Main.js
+
+@implementation JSMain
+
+- (NSString *)getLanguage
+{
+    return [self.js executeJavaScript: Main_getLanguage nargs: 0];
+}
+
+- (void)setLanguage:(NSString *)language
+{
+    [self.js executeJavaScript: Main_setLanguage nargs: 1, language];
+}
+
+- (NSString *)setGenerator:(NSString *)generator
+{
+    return [self.js executeJavaScript: Main_setGenerator nargs: 1, generator];
+}
+
+- (BOOL)prepareForSave
+{
+    NSString *result = [self.js executeJavaScript: Main_prepareForSave nargs: 0];
+    return [@"true" isEqualToString: result];
+}
+
+- (NSString *)getHTML;
+{
+    return [self.js executeJavaScript: Main_getHTML nargs: 0];
+}
+
+- (BOOL)isEmptyDocument
+{
+    NSString *result = [self.js executeJavaScript: Main_isEmptyDocument nargs: 0];
+    return [result isEqualToString: @"true"];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                           JSMetadata                                           //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSMetadata
+
+- (NSDictionary *)getMetadata
+{
+    return [self.js executeJavaScriptJSON: Metadata_getMetadata nargs: 0];
+}
+
+- (void)setMetadata:(NSDictionary *)metadata
+{
+    [self.js executeJavaScriptJSON: Metadata_setMetadata nargs: 1, metadata];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                            JSOutline                                           //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Functions implemented in Outline.js
+
+@implementation JSOutline
+
+- (NSDictionary *)getOutline
+{
+    return [self.js executeJavaScriptJSON: Outline_getOutline nargs: 0];
+}
+
+- (void)moveSection:(NSString *)sectionId parentId:(NSString *)parentId nextId:(NSString *)nextId
+{
+    [self.js executeJavaScript: Outline_moveSection nargs: 3, sectionId, parentId, nextId];
+}
+
+- (void)deleteItem:(NSString *)itemId
+{
+    [self.js executeJavaScript: Outline_deleteItem nargs: 1, itemId];
+}
+
+- (void)scheduleUpdateStructure
+{
+    [self.js executeJavaScript: Outline_scheduleUpdateStructure nargs: 0];
+}
+
+- (void)goToItem:(NSString *)itemId
+{
+    [self.js executeJavaScript: Outline_goToItem nargs: 1, itemId];
+}
+
+- (void)set:(NSString *)itemId numbered:(BOOL)numbered
+{
+    [self.js executeJavaScript: Outline_setNumbered nargs: 2, itemId, [NSNumber numberWithBool: numbered]];
+}
+
+- (void)set:(NSString *)itemId title:(NSString *)title
+{
+    [self.js executeJavaScript: Outline_setTitle nargs: 2, itemId, title];
+}
+
+- (void)insertTableOfContents
+{
+    [self.js executeJavaScript: Outline_insertTableOfContents nargs: 0];
+}
+
+- (void)insertListOfFigures
+{
+    [self.js executeJavaScript: Outline_insertListOfFigures nargs: 0];
+}
+
+- (void)insertListOfTables
+{
+    [self.js executeJavaScript: Outline_insertListOfTables nargs: 0];
+}
+
+- (void)setPrintMode:(BOOL)printMode
+{
+    [self.js executeJavaScript: Outline_setPrintMode nargs: 1, [NSNumber numberWithBool: printMode]];
+}
+
+- (NSDictionary *)examinePrintLayout:(int)pageHeight
+{
+    return [self.js executeJavaScriptJSON: Outline_examinePrintLayout nargs: 1,
+            [NSNumber numberWithInt: pageHeight]];
+}
+
+- (BOOL)detectSectionNumbering
+{
+    NSString *result = [self.js executeJavaScript: Outline_detectSectionNumbering nargs: 0];
+    return [result isEqualToString: @"true"];
+}
+
+- (NSDictionary *)findUsedStyles
+{
+    return [self.js executeJavaScriptJSON: Outline_findUsedStyles nargs: 0];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                            JSPreview                                           //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSPreview
+
+- (void)showForStyle:(NSString *)styleId uiName:(NSString *)uiName title:(NSString *)title
+{
+    [self.js executeJavaScript: Preview_showForStyle nargs: 3, styleId, uiName, title];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                             JSScan                                             //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSScan
+
+- (void)reset
+{
+    [self.js executeJavaScript: Scan_reset nargs: 0];
+}
+
+- (EDScanParagraph *)next
+{
+    NSDictionary *dict = [self.js executeJavaScriptJSON: Scan_next nargs: 0];
+    if ((dict == nil) || ![dict isKindOfClass: [NSDictionary class]])
+        return nil;
+
+    NSString *text = FCGetString(dict,@"text",nil);
+    NSString *sectionId = FCGetString(dict,@"sectionId",nil);
+    if (text == nil)
+        return nil;
+
+    return [[EDScanParagraph alloc] initWithText: text sectionId: sectionId];
+}
+
+- (int)addMatchStart:(int)start end:(int)end
+{
+    return [self.js executeJavaScript: Scan_addMatch nargs: 2,
+            [NSNumber numberWithInt: start],
+            [NSNumber numberWithInt: end]].intValue;
+}
+
+- (void)showMatch:(int)matchId
+{
+    [self.js executeJavaScript: Scan_showMatch nargs: 1, [NSNumber numberWithInt: matchId]];
+}
+
+- (void)replaceMatch:(int)matchId with:(NSString *)text
+{
+    [self.js executeJavaScript: Scan_replaceMatch nargs: 2, [NSNumber numberWithInt: matchId], text];
+}
+
+- (void)removeMatch:(int)matchId
+{
+    [self.js executeJavaScript: Scan_removeMatch nargs: 1, [NSNumber numberWithInt: matchId]];
+}
+
+- (void)goToMatch:(int)matchId
+{
+    [self.js executeJavaScript: Scan_goToMatch nargs: 1, [NSNumber numberWithInt: matchId]];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                           JSSelection                                          //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Functions implemented in Selection.js
+
+@implementation JSSelection
+
+- (void)update
+{
+    [self.js executeJavaScript: Selection_update nargs: 0];
+}
+
+- (void)selectAll
+{
+    [self.js executeJavaScript: Selection_selectAll nargs: 0];
+}
+
+- (void)selectParagraph
+{
+    [self.js executeJavaScript: Selection_selectParagraph nargs: 0];
+}
+
+- (void)selectWordAtCursor
+{
+    [self.js executeJavaScript: Selection_selectWordAtCursor nargs: 0];
+}
+
+- (NSString *)dragSelectionBeginX:(int)x y:(int)y selectWord:(BOOL)selectWord
+{
+    return [self.js executeJavaScript: Selection_dragSelectionBegin nargs: 3,
+            [NSNumber numberWithInt: x], [NSNumber numberWithInt: y],
+            [NSNumber numberWithBool: selectWord]];
+}
+
+- (NSString *)dragSelectionUpdateX:(int)x y:(int)y selectWord:(BOOL)selectWord
+{
+    return [self.js executeJavaScript: Selection_dragSelectionUpdate nargs: 3,
+            [NSNumber numberWithInt: x], [NSNumber numberWithInt: y],
+            [NSNumber numberWithBool: selectWord]];
+}
+
+- (NSString *)moveStartLeft
+{
+    return [self.js executeJavaScript: Selection_moveStartLeft nargs: 0];
+}
+
+- (NSString *)moveStartRight
+{
+    return [self.js executeJavaScript: Selection_moveStartRight nargs: 0];
+}
+
+- (NSString *)moveEndLeft
+{
+    return [self.js executeJavaScript: Selection_moveEndLeft nargs: 0];
+}
+
+- (NSString *)moveEndRight
+{
+    return [self.js executeJavaScript: Selection_moveEndRight nargs: 0];
+}
+
+- (void)setSelectionStartAtCoordsX:(int)x y:(int)y
+{
+    [self.js executeJavaScript: Selection_setSelectionStartAtCoords nargs: 2,
+                             [NSNumber numberWithInt: x], [NSNumber numberWithInt: y]];
+}
+
+- (void)setSelectionEndAtCoordsX:(int)x y:(int)y
+{
+    [self.js executeJavaScript: Selection_setSelectionEndAtCoords nargs: 2,
+                             [NSNumber numberWithInt: x], [NSNumber numberWithInt: y]];
+}
+
+- (void)setTableSelectionEdge:(NSString *)edge atCoordsX:(int)x y:(int)y
+{
+    [self.js executeJavaScript: Selection_setTableSelectionEdgeAtCoords nargs: 3,
+                           edge, [NSNumber numberWithInt: x], [NSNumber numberWithInt: y]];
+}
+
+- (void)print
+{
+    [self.js executeJavaScript: Selection_print nargs: 0];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                            JSStyles                                            //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSStyles
+
+- (NSString *)getCSSText
+{
+    return [self.js executeJavaScript: Styles_getCSSText nargs: 0];
+}
+
+- (void)setCSSText:(NSString *)cssText rules:(NSDictionary *)rules
+{
+//    debug(@"---------------------- setCSSText ----------------------\n");
+//    debug(@"%@",cssText);
+//    if ((cssText.length > 0) && ([cssText characterAtIndex: cssText.length-1] != '\n'))
+//        debug(@"\n");
+//    debug(@"--------------------------------------------------------\n");
+    [self.js executeJavaScriptJSON: Styles_setCSSText nargs: 2, cssText, rules];
+}
+
+- (NSString *)paragraphClass
+{
+    return [self.js executeJavaScript: Styles_getParagraphClass nargs: 0];
+}
+
+- (void)setParagraphClass:(NSString *)paragraphClass;
+{
+    [self.js executeJavaScript: Styles_setParagraphClass nargs: 1, paragraphClass];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                            JSTables                                            //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Functions implemented in Tables.js
+
+@implementation JSTables
+
+- (void)insertTableRows:(int)rows cols:(int)cols width:(NSString *)width numbered:(BOOL)numbered
+                caption:(NSString *)caption className:(NSString *)className;
+{
+    [self.js executeJavaScript: Tables_insertTable nargs: 6,
+                             [NSNumber numberWithInt: rows], [NSNumber numberWithInt: cols],
+                             width, [NSNumber numberWithBool: numbered], caption, className];
+}
+
+- (void)addAdjacentRow
+{
+    [self.js executeJavaScript: Tables_addAdjacentRow nargs: 0];
+}
+
+- (void)addAdjacentColumn
+{
+    [self.js executeJavaScript: Tables_addAdjacentColumn nargs: 0];
+}
+
+- (void)removeAdjacentRow
+{
+    [self.js executeJavaScript: Tables_removeAdjacentRow nargs: 0];
+}
+
+- (void)removeAdjacentColumn
+{
+    [self.js executeJavaScript: Tables_removeAdjacentColumn nargs: 0];
+}
+
+- (void)clearCells
+{
+    [self.js executeJavaScript: Tables_clearCells nargs: 0];
+}
+
+- (void)mergeCells
+{
+    [self.js executeJavaScript: Tables_mergeCells nargs: 0];
+}
+
+- (void)splitSelection
+{
+    [self.js executeJavaScript: Tables_splitSelection nargs: 0];
+}
+
+- (NSString *)getSelectedTableId
+{
+    return [self.js executeJavaScript: Tables_getSelectedTableId nargs: 0];
+}
+
+- (NSDictionary *)getProperties:(NSString *)itemId
+{
+    return [self.js executeJavaScriptJSON: Tables_getProperties nargs: 1, itemId];
+}
+
+- (void)setProperties:(NSString *)itemId width:(NSString *)width
+{
+    [self.js executeJavaScript: Tables_setProperties nargs: 2, itemId, width];
+}
+
+- (void)set:(NSString *)itemId colWidths:(NSArray *)colWidths
+{
+    [self.js executeJavaScript: Tables_setColWidths nargs: 2, itemId, colWidths];
+}
+
+- (NSDictionary *)getGeometry:(NSString *)itemId
+{
+    return [self.js executeJavaScriptJSON: Tables_getGeometry nargs: 1, itemId];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                          JSUndoManager                                         //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation JSUndoManager
+
+- (int)getLength
+{
+    NSString *result = [self.js executeJavaScript: UndoManager_getLength nargs: 0];
+    return result.intValue;
+}
+
+- (int)getIndex
+{
+    NSString *result = [self.js executeJavaScript: UndoManager_getIndex nargs: 0];
+    return result.intValue;
+}
+
+- (void)setIndex:(int)index
+{
+    [self.js executeJavaScript: UndoManager_setIndex nargs: 1, [NSNumber numberWithInt: index]];
+}
+
+- (void)undo
+{
+    [self.js executeJavaScript: UndoManager_undo nargs: 0];
+}
+
+- (void)redo
+{
+    [self.js executeJavaScript: UndoManager_redo nargs: 0];
+}
+
+- (void)newGroup:(NSString *)name
+{
+    [self.js executeJavaScript: UndoManager_newGroup nargs: 1, name];
+}
+
+- (NSString *)groupType
+{
+    return [self.js executeJavaScript: UndoManager_groupType nargs: 0];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                           JSViewport                                           //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Functions implemented in Viewport.js
+
+@implementation JSViewport
+
+- (void)setViewportWidth:(int)width
+{
+    [self.js executeJavaScript: Viewport_setViewportWidth nargs: 1, [NSNumber numberWithInt: width]];
+}
+
+- (void)setTextScale:(int)textScale
+{
+    [self.js executeJavaScript: Viewport_setTextScale nargs: 1, [NSNumber numberWithInt: textScale]];
+}
+
+@end
diff --git a/sample/code/objc_bindings/WARNING b/sample/code/objc_bindings/WARNING
new file mode 100644
index 0000000..cbc20f2
--- /dev/null
+++ b/sample/code/objc_bindings/WARNING
@@ -0,0 +1,12 @@
+IMPORTANT NOTE: This code does not work in it's current form, and exists for
+illustrative purposes only. It is an excerpt from the UX Write source code
+indented to show how the bindings between Objective C and JavaScript are
+implemented, both in terms of calling *in* to JavaScript, and calling *out* of
+JavaScript (that is, callback functions).
+
+The files in this directory should be considered temporary. They are here for
+the purpose of demonstrating to developers of various bindings how this can be
+achieved. It is envisaged that once there is at least one binding that has been
+developed purely as part of the Corinthia project, that will serve as the
+example for any future bindings, and the Objective-C/Apple-specific files can be
+removed.
diff --git a/sample/documents/INDEX b/sample/documents/INDEX
new file mode 100644
index 0000000..de74ddc
--- /dev/null
+++ b/sample/documents/INDEX
@@ -0,0 +1,29 @@
+This directory contains various files in the document formats that
+Corinthia supports.
+
+Contents of /html
+
+Name:                  Tags:
+----------------------------------------------------------------------
+h1-6_center_p.html     H1-H6, b, i, u, p, center, bgcolor
+lists.html             ul, ol ,li
+tables.html            tr, td, th, border, cellpadding, br
+
+Contents of /docx
+
+Name:                  Tags:
+----------------------------------------------------------------------
+
+
+Contents of /odf
+
+Name:                  Tags:
+----------------------------------------------------------------------
+
+
+Contents of /tex
+
+Name:                  Tags:
+----------------------------------------------------------------------
+
+
diff --git a/sample/documents/docx/we-need-more-samples b/sample/documents/docx/we-need-more-samples
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sample/documents/docx/we-need-more-samples
diff --git a/sample/documents/html/h1-6_center_p.html b/sample/documents/html/h1-6_center_p.html
new file mode 100644
index 0000000..afdd014
--- /dev/null
+++ b/sample/documents/html/h1-6_center_p.html
@@ -0,0 +1,27 @@
+<head>
+<title>HTML: Headers 1-6, comment, center, paragraph</title>
+</head>
+<body bgcolor="PINK">
+
+<h1>This is a H1 header</h1>
+<h2>This is a H2 header</h2>
+<h3>This is a H3 header</h3>
+<h4>This is a H4 header</h4>
+<h5>This is a H5 header</h5>
+<h6>This is a H6 header</H6>
+
+<!-- This is a comment -->
+
+<center>This sentence is centered.</center>
+
+<p>This is a paragraph with five sentences, this sentence is plain.
+<b>This is a paragraph with five sentences, this sentence is bold.</b>
+<u>This is a paragraph with five sentences, this sentence is
+underlined.</u>
+<i>This is a paragraph with five sentences, this
+sentence is slanted.</i>
+<b><i>This is a paragraph with five
+sentences, this sentence is bold and slanted.</b></i>
+</p>
+
+</body>
diff --git a/sample/documents/html/lists.html b/sample/documents/html/lists.html
new file mode 100644
index 0000000..6a932c1
--- /dev/null
+++ b/sample/documents/html/lists.html
@@ -0,0 +1,18 @@
+<head>
+<title>HTML: Lists</title>
+</head>
+<body bgcolor="BLUE">
+
+<ol> Ordered List:
+  <li> Item 1 </li>
+  <li> Item 2 </li>
+  <li> Item 3 </li>
+</ol>
+
+<ul> Bulleted List:
+  <li> Item 1 </li>
+  <li> Item 2 </li>
+  <li> Item 3 </li>
+</ul>
+
+</body>
diff --git a/sample/documents/html/simple_1.html b/sample/documents/html/simple_1.html
new file mode 100644
index 0000000..6a932c1
--- /dev/null
+++ b/sample/documents/html/simple_1.html
@@ -0,0 +1,18 @@
+<head>
+<title>HTML: Lists</title>
+</head>
+<body bgcolor="BLUE">
+
+<ol> Ordered List:
+  <li> Item 1 </li>
+  <li> Item 2 </li>
+  <li> Item 3 </li>
+</ol>
+
+<ul> Bulleted List:
+  <li> Item 1 </li>
+  <li> Item 2 </li>
+  <li> Item 3 </li>
+</ul>
+
+</body>
diff --git a/sample/documents/html/table.html b/sample/documents/html/table.html
new file mode 100644
index 0000000..18cd7ab
--- /dev/null
+++ b/sample/documents/html/table.html
@@ -0,0 +1,33 @@
+<head>
+<title>HTML: Tables</title>
+</head>
+<body bgcolor="YELLOW">
+
+<table border="2">
+  <tr>
+    <td>Cell Line 1 (right)</td>
+    <td>cell Line 1 (left)</td>
+  </tr>
+  <tr>
+    <td>Cell Line 2 (right)</td>
+    <td>cell Line 2 (left)</td>
+  </tr>
+</table>
+<br/>
+<br/>
+<br/>
+<table cellpadding=5 border="5">
+  <tr>
+    <th>Column 1</th>
+    <th>Column 2</th>
+  </tr>
+  <tr>
+    <td>Line 1 column 1</td>
+    <td>Line 1 column 2</td>
+  </tr>
+  <tr>
+    <td>Line 2 column 1</td>
+    <td>Line 2 column 2</td>
+  </tr>
+</table>
+</body>
diff --git a/sample/documents/odf/we-need-more-samples b/sample/documents/odf/we-need-more-samples
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sample/documents/odf/we-need-more-samples
diff --git a/sample/documents/tex/we-need-more-samples b/sample/documents/tex/we-need-more-samples
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sample/documents/tex/we-need-more-samples
diff --git a/sample/documents/we-need-more-samples b/sample/documents/we-need-more-samples
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sample/documents/we-need-more-samples
diff --git a/schemas/createimpl.js b/schemas/createimpl.js
index 1d65042..e3ad79d 100755
--- a/schemas/createimpl.js
+++ b/schemas/createimpl.js
@@ -1,18 +1,21 @@
 #!/usr/local/bin/phantomjs --web-security=no
 
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 var autoGeneratedMsg = "// This file was automatically generated using schemas/generate.sh. "+
                        "Do not edit.";
diff --git a/schemas/relaxng.js b/schemas/relaxng.js
index f73a668..233a263 100755
--- a/schemas/relaxng.js
+++ b/schemas/relaxng.js
@@ -1,18 +1,21 @@
 #!/usr/local/bin/phantomjs --web-security=no
 
-// Copyright 2012-2014 UX Productivity Pty Ltd
+// 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
 //
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
-// 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.
+// 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.
 
 /*