[med-svn] [orthanc] 01/04: New upstream version 1.2.0+dfsg

Sebastien Jodogne jodogne-guest at moszumanska.debian.org
Tue Dec 13 20:17:27 UTC 2016


This is an automated email from the git hooks/post-receive script.

jodogne-guest pushed a commit to branch master
in repository orthanc.

commit 2fdcb0555749510d6304a512a31fb0192ded2e59
Author: jodogne-guest <s.jodogne at gmail.com>
Date:   Tue Dec 13 20:39:39 2016 +0100

    New upstream version 1.2.0+dfsg
---
 .hg_archival.txt                                   |    6 +-
 CMakeLists.txt                                     |   41 +-
 Core/Cache/SharedArchive.cpp                       |    5 +-
 Core/DicomFormat/DicomArray.h                      |    2 +-
 Core/DicomFormat/DicomImageInformation.h           |    2 +-
 Core/DicomFormat/DicomMap.h                        |    2 +-
 Core/DicomFormat/DicomTag.h                        |    2 +
 Core/DicomFormat/DicomValue.cpp                    |    2 +-
 Core/DicomFormat/DicomValue.h                      |    7 +-
 Core/Enumerations.cpp                              |   20 +-
 Core/Enumerations.h                                |    8 +-
 Core/FileStorage/FilesystemStorage.cpp             |   66 +-
 Core/FileStorage/FilesystemStorage.h               |    2 +-
 Core/FileStorage/StorageAccessor.cpp               |    4 +-
 Core/HttpClient.cpp                                |   84 +-
 Core/HttpClient.h                                  |   24 +
 Core/HttpServer/FilesystemHttpHandler.cpp          |    5 +-
 Core/HttpServer/FilesystemHttpSender.h             |    4 +-
 Core/HttpServer/HttpOutput.cpp                     |    3 +-
 Core/HttpServer/HttpOutput.h                       |    9 +-
 Core/HttpServer/HttpStreamTranscoder.h             |    1 +
 Core/HttpServer/IHttpHandler.h                     |    2 +-
 Core/HttpServer/MongooseServer.cpp                 |  153 +-
 Core/Images/Font.cpp                               |    3 +-
 Core/{Pkcs11.h => Images/IImageWriter.cpp}         |   30 +-
 Core/Images/IImageWriter.h                         |   16 +-
 .../Semaphore.cpp => Images/Image.cpp}             |   38 +-
 Core/Images/Image.h                                |   10 +-
 Core/Images/ImageAccessor.cpp                      |   18 +
 Core/Images/ImageAccessor.h                        |    2 +
 Core/Images/ImageBuffer.cpp                        |   14 +-
 Core/Images/ImageBuffer.h                          |    5 +-
 Core/Images/ImageProcessing.cpp                    |   76 +
 Core/Images/ImageProcessing.h                      |    6 +
 Core/Images/JpegReader.cpp                         |   14 +-
 Core/Images/JpegReader.h                           |    6 +
 Core/Images/JpegWriter.cpp                         |   11 +-
 Core/Images/JpegWriter.h                           |    2 +
 Core/Images/PngReader.cpp                          |   11 +-
 Core/Images/PngReader.h                            |    6 +
 Core/Images/PngWriter.cpp                          |    9 +-
 Core/Images/PngWriter.h                            |    2 +
 Core/Logging.cpp                                   |  197 +-
 Core/Logging.h                                     |   16 +
 Core/Lua/LuaContext.cpp                            |    4 +
 Core/Lua/LuaFunctionCall.cpp                       |   22 +
 Core/Lua/LuaFunctionCall.h                         |    7 +
 Core/MultiThreading/BagOfTasksProcessor.cpp        |   41 +-
 Core/MultiThreading/BagOfTasksProcessor.h          |   13 +-
 Core/MultiThreading/ReaderWriterLock.cpp           |    5 +-
 Core/MultiThreading/RunnableWorkersPool.cpp        |   26 +-
 Core/MultiThreading/RunnableWorkersPool.h          |    2 +-
 Core/MultiThreading/Semaphore.cpp                  |    4 -
 Core/MultiThreading/Semaphore.h                    |   18 +
 Core/MultiThreading/SharedMessageQueue.cpp         |   20 +
 Core/MultiThreading/SharedMessageQueue.h           |    2 +
 Core/OrthancException.h                            |    2 +-
 Core/Pkcs11.cpp                                    |   12 +-
 Core/Pkcs11.h                                      |   18 +-
 Core/PrecompiledHeaders.h                          |    3 +-
 Core/RestApi/RestApi.cpp                           |    2 +-
 Core/RestApi/RestApiOutput.cpp                     |    7 +-
 Core/SystemToolbox.cpp                             |  539 ++++
 Core/{OrthancException.h => SystemToolbox.h}       |   98 +-
 Core/{Uuid.h => TemporaryFile.cpp}                 |   82 +-
 Core/{Images/JpegReader.h => TemporaryFile.h}      |   31 +-
 Core/Toolbox.cpp                                   |  641 ++---
 Core/Toolbox.h                                     |  105 +-
 Core/Uuid.cpp                                      |  162 --
 Core/WebServiceParameters.cpp                      |   12 +-
 Core/WebServiceParameters.h                        |    6 +
 DarwinCompilation.txt                              |    6 +-
 INSTALL                                            |   15 +-
 LinuxCompilation.txt                               |   43 +-
 NEWS                                               |   72 +-
 OrthancExplorer/explorer.html                      |   34 +-
 OrthancExplorer/explorer.js                        |   82 +-
 OrthancExplorer/file-upload.js                     |    5 +
 OrthancExplorer/query-retrieve.js                  |  616 ++--
 OrthancServer/DatabaseWrapper.cpp                  |    9 +-
 OrthancServer/DicomDirWriter.cpp                   |    8 +-
 OrthancServer/DicomInstanceToStore.cpp             |   36 +-
 OrthancServer/DicomInstanceToStore.h               |    2 +
 OrthancServer/DicomModification.cpp                |   38 +-
 OrthancServer/DicomModification.h                  |    2 +
 OrthancServer/DicomProtocol/DicomFindAnswers.cpp   |  117 +-
 OrthancServer/DicomProtocol/DicomFindAnswers.h     |   28 +-
 OrthancServer/DicomProtocol/DicomServer.cpp        |   14 +-
 OrthancServer/DicomProtocol/DicomServer.h          |    6 +-
 .../DicomProtocol/DicomUserConnection.cpp          |  115 +-
 OrthancServer/DicomProtocol/DicomUserConnection.h  |   21 +
 OrthancServer/DicomProtocol/IMoveRequestHandler.h  |    8 +-
 OrthancServer/FromDcmtkBridge.cpp                  |  395 ++-
 OrthancServer/FromDcmtkBridge.h                    |   95 +-
 OrthancServer/Internals/CommandDispatcher.cpp      |   41 +-
 OrthancServer/Internals/CommandDispatcher.h        |   19 +-
 OrthancServer/Internals/DicomFrameIndex.cpp        |    3 +-
 OrthancServer/Internals/DicomImageDecoder.cpp      |   20 +-
 OrthancServer/Internals/DicomImageDecoder.h        |    9 +
 OrthancServer/Internals/FindScp.cpp                |   72 +-
 OrthancServer/Internals/MoveScp.cpp                |   46 +-
 OrthancServer/Internals/StoreScp.cpp               |   13 +-
 OrthancServer/LuaScripting.cpp                     |    5 +-
 OrthancServer/OrthancFindRequestHandler.cpp        |  124 +-
 OrthancServer/OrthancInitialization.cpp            |  107 +-
 OrthancServer/OrthancInitialization.h              |   23 +
 OrthancServer/OrthancMoveRequestHandler.cpp        |   55 +-
 OrthancServer/OrthancMoveRequestHandler.h          |    6 +-
 .../OrthancRestApi/OrthancRestAnonymizeModify.cpp  |   15 +-
 .../OrthancRestApi/OrthancRestArchive.cpp          |   10 +-
 .../OrthancRestApi/OrthancRestModalities.cpp       |  120 +-
 .../OrthancRestApi/OrthancRestResources.cpp        |  127 +-
 OrthancServer/OrthancRestApi/OrthancRestSystem.cpp |   33 +-
 OrthancServer/ParsedDicomFile.cpp                  |  114 +-
 OrthancServer/ParsedDicomFile.h                    |   33 +-
 OrthancServer/QueryRetrieveHandler.cpp             |   54 +-
 OrthancServer/Scheduler/CallSystemCommand.cpp      |    8 +-
 OrthancServer/Scheduler/ServerJob.cpp              |    4 +-
 OrthancServer/Scheduler/ServerScheduler.cpp        |    7 +-
 OrthancServer/Scheduler/ServerScheduler.h          |    2 +-
 OrthancServer/Scheduler/StorePeerCommand.cpp       |    2 +-
 OrthancServer/Scheduler/StoreScuCommand.cpp        |   18 +-
 OrthancServer/Scheduler/StoreScuCommand.h          |    8 +-
 OrthancServer/Search/HierarchicalMatcher.cpp       |    4 +-
 OrthancServer/Search/LookupIdentifierQuery.cpp     |  134 +-
 OrthancServer/Search/LookupIdentifierQuery.h       |   20 +-
 OrthancServer/Search/LookupResource.cpp            |   10 +-
 OrthancServer/ServerContext.cpp                    |  104 +-
 OrthancServer/ServerContext.h                      |   32 +-
 OrthancServer/ServerEnumerations.cpp               |    2 +
 OrthancServer/ServerEnumerations.h                 |    4 +-
 OrthancServer/ServerIndex.cpp                      |  149 +-
 OrthancServer/ServerIndex.h                        |    8 +
 OrthancServer/ServerIndexChange.h                  |    4 +-
 OrthancServer/ServerToolbox.cpp                    |  190 +-
 OrthancServer/ServerToolbox.h                      |   25 +-
 OrthancServer/ToDcmtkBridge.cpp                    |   18 -
 OrthancServer/ToDcmtkBridge.h                      |    2 -
 OrthancServer/main.cpp                             |   75 +-
 Plugins/Engine/IPluginServiceProvider.h            |    2 +-
 Plugins/Engine/OrthancPluginDatabase.cpp           |    2 +-
 Plugins/Engine/OrthancPluginDatabase.h             |    2 +-
 Plugins/Engine/OrthancPlugins.cpp                  |  101 +-
 Plugins/Engine/OrthancPlugins.h                    |    7 +-
 Plugins/Engine/PluginsEnumerations.cpp             |    2 +-
 Plugins/Engine/PluginsEnumerations.h               |    2 +-
 Plugins/Engine/PluginsErrorDictionary.cpp          |    2 +-
 Plugins/Engine/PluginsErrorDictionary.h            |    2 +-
 Plugins/Engine/PluginsManager.cpp                  |    2 +-
 Plugins/Engine/PluginsManager.h                    |    2 +-
 Plugins/Engine/SharedLibrary.cpp                   |    2 +-
 Plugins/Engine/SharedLibrary.h                     |    4 +-
 Plugins/Include/orthanc/OrthancCPlugin.h           |  207 +-
 Plugins/Samples/Basic/Plugin.c                     |   44 +-
 Plugins/Samples/Common/DicomDatasetReader.cpp      |  122 +
 .../Samples/Common/DicomDatasetReader.h            |   30 +-
 .../Samples/Common/DicomPath.cpp                   |   77 +-
 .../Samples/Common/DicomPath.h                     |   94 +-
 .../Samples/Common/DicomTag.cpp                    |  115 +-
 Plugins/Samples/Common/DicomTag.h                  |   95 +
 Plugins/Samples/Common/FullOrthancDataset.cpp      |  196 ++
 .../Samples/Common/FullOrthancDataset.h            |   36 +-
 .../Samples/Common/IDicomDataset.h                 |   24 +-
 .../Samples/Common/IOrthancConnection.cpp          |   78 +-
 .../Common/IOrthancConnection.h}                   |   72 +-
 .../Samples/Common/OrthancHttpConnection.cpp       |  107 +-
 .../Common/OrthancHttpConnection.h}                |   53 +-
 .../Samples/Common/OrthancPluginConnection.cpp     |  105 +-
 .../Common/OrthancPluginConnection.h}              |   50 +-
 Plugins/Samples/Common/OrthancPluginCppWrapper.cpp |  383 ++-
 Plugins/Samples/Common/OrthancPluginCppWrapper.h   |  226 +-
 Plugins/Samples/Common/OrthancPlugins.cmake        |    5 +-
 .../Samples/Common/SimplifiedOrthancDataset.cpp    |  156 +
 .../Samples/Common/SimplifiedOrthancDataset.h      |   36 +-
 Plugins/Samples/DatabasePlugin/CMakeLists.txt      |    7 +-
 Plugins/Samples/ModalityWorklists/CMakeLists.txt   |    1 +
 Plugins/Samples/ModalityWorklists/Plugin.cpp       |  256 +-
 Plugins/Samples/ModalityWorklists/README           |   57 +-
 Plugins/Samples/ServeFolders/CMakeLists.txt        |    3 +
 Plugins/Samples/ServeFolders/Plugin.cpp            |  412 +--
 Plugins/Samples/ServeFolders/README                |   53 +-
 README                                             |   10 +-
 Resources/CMake/BoostConfiguration.cmake           |   46 +-
 Resources/CMake/Compiler.cmake                     |   29 +-
 Resources/CMake/DcmtkConfiguration.cmake           |   44 +-
 Resources/CMake/DownloadPackage.cmake              |   22 +-
 Resources/CMake/GoogleTestConfiguration.cmake      |   29 +-
 Resources/CMake/JsonCppConfiguration.cmake         |    2 +-
 Resources/CMake/LibCurlConfiguration.cmake         |   27 +-
 Resources/CMake/LibIconvConfiguration.cmake        |    4 +-
 Resources/CMake/LibJpegConfiguration.cmake         |    4 +-
 Resources/CMake/LibP11Configuration.cmake          |    4 +-
 Resources/CMake/LibPngConfiguration.cmake          |    4 +-
 Resources/CMake/LuaConfiguration.cmake             |    2 +-
 Resources/CMake/MongooseConfiguration.cmake        |    4 +-
 Resources/CMake/OpenSslConfiguration.cmake         |    7 +-
 Resources/CMake/PugixmlConfiguration.cmake         |    8 +-
 Resources/CMake/SQLiteConfiguration.cmake          |    2 +-
 Resources/CMake/ZlibConfiguration.cmake            |    6 +-
 Resources/Configuration.json                       |   47 +-
 Resources/DicomConformanceStatement.txt            |    2 +-
 Resources/EmbedResources.py                        |    4 +
 Resources/ErrorCodes.json                          |    7 +-
 Resources/Orthanc.doxygen                          | 2354 +++++++++------
 Resources/OrthancPlugin.doxygen                    | 2359 +++++++++------
 .../dcmtk-3.6.0-dulparse-vulnerability.patch       |   29 +
 Resources/Patches/dcmtk-3.6.1-private.dic          | 3040 ++++++++++++++++++++
 Resources/Patches/dcmtk.txt                        |    9 +
 .../Samples/Python/ArchiveStudiesInTimeRange.py    |   16 +-
 Resources/Samples/Python/AutoClassify.py           |   14 +-
 Resources/Samples/Python/DownloadAnonymized.py     |    5 +-
 Resources/Samples/Tools/CMakeLists.txt             |   10 +-
 Resources/Samples/Tools/RecoverCompressedFile.cpp  |    6 +-
 .../Samples/WebApplications/DrawingDicomizer.js    |    4 +-
 Resources/ThirdParty/VisualStudio/stdint.h         |  506 ++--
 Resources/ThirdParty/base64/base64.cpp             |  256 +-
 Resources/ThirdParty/base64/base64.h               |    8 +-
 THANKS                                             |   65 -
 TODO                                               |  152 +
 UnitTestsSources/DicomMapTests.cpp                 |    3 +-
 UnitTestsSources/FileStorageTests.cpp              |   13 +-
 UnitTestsSources/FromDcmtkTests.cpp                |  361 ++-
 UnitTestsSources/ImageTests.cpp                    |   20 +-
 UnitTestsSources/JpegLosslessTests.cpp             |    2 +-
 UnitTestsSources/LuaTests.cpp                      |    4 +-
 UnitTestsSources/MultiThreadingTests.cpp           |    9 +-
 UnitTestsSources/PluginsTests.cpp                  |    2 +-
 UnitTestsSources/RestApiTests.cpp                  |   15 +-
 UnitTestsSources/SQLiteTests.cpp                   |    4 +-
 UnitTestsSources/ServerIndexTests.cpp              |   23 +-
 UnitTestsSources/StreamTests.cpp                   |   15 +-
 UnitTestsSources/UnitTestsMain.cpp                 |   65 +-
 UnitTestsSources/VersionsTests.cpp                 |    8 +-
 233 files changed, 13358 insertions(+), 6041 deletions(-)

diff --git a/.hg_archival.txt b/.hg_archival.txt
index fa815d1..68a52ba 100644
--- a/.hg_archival.txt
+++ b/.hg_archival.txt
@@ -1,5 +1,5 @@
 repo: 3959d33612ccaadc0d4d707227fbed09ac35e5fe
-node: 8fdeb348f72be7848a1b227a77a7a6adc7153286
-branch: Orthanc-1.1.0
+node: 2bdc29af95895479178be61a219977e861c90645
+branch: Orthanc-1.2.0
 latesttag: null
-latesttagdistance: 1779
+latesttagdistance: 1946
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a0a3fe3..5b75105 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8)
 project(Orthanc)
 
 # Version of the build, should always be "mainline" except in release branches
-set(ORTHANC_VERSION "1.1.0")
+set(ORTHANC_VERSION "1.2.0")
 
 # Version of the database schema. History:
 #   * Orthanc 0.1.0 -> Orthanc 0.3.0 = no versioning
@@ -32,8 +32,8 @@ SET(ENABLE_PLUGINS ON CACHE BOOL "Enable plugins")
 SET(BUILD_SERVE_FOLDERS ON CACHE BOOL "Whether to build the ServeFolders plugin")
 SET(BUILD_MODALITY_WORKLISTS ON CACHE BOOL "Whether to build the sample plugin to serve modality worklists")
 SET(BUILD_RECOVER_COMPRESSED_FILE ON CACHE BOOL "Whether to build the companion tool to recover files compressed using Orthanc")
-SET(USE_DCMTK_361 OFF CACHE BOOL "Use forthcoming DCMTK version 3.6.1 in static builds (instead of 3.6.0)")
 SET(ENABLE_PKCS11 OFF CACHE BOOL "Enable PKCS#11 for HTTPS client authentication using hardware security modules and smart cards")
+SET(ENABLE_PROFILING OFF CACHE BOOL "Whether to enable the generation of profiling information with gprof")
 
 # Advanced parameters to fine-tune linking against system libraries
 SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp")
@@ -51,8 +51,10 @@ SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib")
 SET(USE_SYSTEM_PUGIXML ON CACHE BOOL "Use the system version of Pugixml")
 SET(USE_SYSTEM_LIBP11 OFF CACHE BOOL "Use the system version of libp11 (PKCS#11 wrapper library)")
 
-# Experimental options
+# Advanced parameters
 SET(USE_PUGIXML ON CACHE BOOL "Use the Pugixml parser (turn off only for debug)")
+SET(USE_DCMTK_361 OFF CACHE BOOL "Use forthcoming DCMTK version 3.6.1 in static builds (instead of 3.6.0)")
+SET(USE_DCMTK_361_PRIVATE_DIC ON CACHE BOOL "Use the dictionary of private tags from DCMTK 3.6.1 in static builds (which is more up-to-date)")
 
 # Distribution-specific settings
 SET(USE_GTEST_DEBIAN_SOURCE_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)")
@@ -130,6 +132,8 @@ set(ORTHANC_CORE_SOURCES
   Core/MultiThreading/SharedMessageQueue.cpp
   Core/Images/Font.cpp
   Core/Images/FontRegistry.cpp
+  Core/Images/IImageWriter.cpp
+  Core/Images/Image.cpp
   Core/Images/ImageAccessor.cpp
   Core/Images/ImageBuffer.cpp
   Core/Images/ImageProcessing.cpp
@@ -144,8 +148,9 @@ set(ORTHANC_CORE_SOURCES
   Core/SQLite/StatementId.cpp
   Core/SQLite/StatementReference.cpp
   Core/SQLite/Transaction.cpp
+  Core/SystemToolbox.cpp
+  Core/TemporaryFile.cpp
   Core/Toolbox.cpp
-  Core/Uuid.cpp
   Core/WebServiceParameters.cpp
   Core/Lua/LuaContext.cpp
   Core/Lua/LuaFunctionCall.cpp
@@ -306,31 +311,31 @@ include(${CMAKE_SOURCE_DIR}/Resources/CMake/DcmtkConfiguration.cmake)
 
 
 if (ENABLE_SSL)
-  add_definitions(-DORTHANC_SSL_ENABLED=1)
+  add_definitions(-DORTHANC_ENABLE_SSL=1)
   include(${CMAKE_SOURCE_DIR}/Resources/CMake/OpenSslConfiguration.cmake)
 else()
-  add_definitions(-DORTHANC_SSL_ENABLED=0)
+  add_definitions(-DORTHANC_ENABLE_SSL=0)
 endif()
 
 
 if (ENABLE_JPEG)
-  add_definitions(-DORTHANC_JPEG_ENABLED=1)
+  add_definitions(-DORTHANC_ENABLE_JPEG=1)
 else()
-  add_definitions(-DORTHANC_JPEG_ENABLED=0)
+  add_definitions(-DORTHANC_ENABLE_JPEG=0)
 endif()
 
 
 if (ENABLE_JPEG_LOSSLESS)
-  add_definitions(-DORTHANC_JPEG_LOSSLESS_ENABLED=1)
+  add_definitions(-DORTHANC_ENABLE_JPEG_LOSSLESS=1)
 else()
-  add_definitions(-DORTHANC_JPEG_LOSSLESS_ENABLED=0)
+  add_definitions(-DORTHANC_ENABLE_JPEG_LOSSLESS=0)
 endif()
 
 
 if (ENABLE_PLUGINS)
-  add_definitions(-DORTHANC_PLUGINS_ENABLED=1)
+  add_definitions(-DORTHANC_ENABLE_PLUGINS=1)
 else()
-  add_definitions(-DORTHANC_PLUGINS_ENABLED=0)
+  add_definitions(-DORTHANC_ENABLE_PLUGINS=0)
 endif()
 
 
@@ -338,13 +343,13 @@ if (ENABLE_PKCS11)
   if (ENABLE_SSL)
     include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibP11Configuration.cmake)
 
-    add_definitions(-DORTHANC_PKCS11_ENABLED=1)
+    add_definitions(-DORTHANC_ENABLE_PKCS11=1)
     list(APPEND ORTHANC_CORE_SOURCES Core/Pkcs11.cpp)
   else()
     message(FATAL_ERROR "OpenSSL is required to enable PKCS#11")
   endif()
 else()
-  add_definitions(-DORTHANC_PKCS11_ENABLED=0)  
+  add_definitions(-DORTHANC_ENABLE_PKCS11=0)  
 endif()
 
 
@@ -404,11 +409,15 @@ include_directories(${CMAKE_SOURCE_DIR}/Plugins/Include)
 add_definitions(
   -DORTHANC_VERSION="${ORTHANC_VERSION}"
   -DORTHANC_DATABASE_VERSION=${ORTHANC_DATABASE_VERSION}
+  -DORTHANC_BUILD_UNIT_TESTS=1
+  -DORTHANC_ENABLE_BASE64=1
   -DORTHANC_ENABLE_LOGGING=1
+  -DORTHANC_ENABLE_MD5=1
   -DORTHANC_MAXIMUM_TAG_LENGTH=256
-  -DORTHANC_BUILD_UNIT_TESTS=1
+  -DORTHANC_SANDBOXED=0
 
   # Macros for the plugins
+  -DHAS_ORTHANC_EXCEPTION=0
   -DMODALITY_WORKLISTS_VERSION="${ORTHANC_VERSION}"
   -DSERVE_FOLDERS_VERSION="${ORTHANC_VERSION}"
   )
@@ -546,6 +555,7 @@ if (ENABLE_PLUGINS AND BUILD_SERVE_FOLDERS)
     ${BOOST_SOURCES}
     ${JSONCPP_SOURCES}
     Plugins/Samples/ServeFolders/Plugin.cpp
+    Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
     ${SERVE_FOLDERS_RESOURCES}
     )
 
@@ -588,6 +598,7 @@ if (ENABLE_PLUGINS AND BUILD_MODALITY_WORKLISTS)
   add_library(ModalityWorklists SHARED 
     ${BOOST_SOURCES}
     ${JSONCPP_SOURCES}
+    Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
     Plugins/Samples/ModalityWorklists/Plugin.cpp
     ${MODALITY_WORKLISTS_RESOURCES}
     )
diff --git a/Core/Cache/SharedArchive.cpp b/Core/Cache/SharedArchive.cpp
index 93303e8..b3cafb5 100644
--- a/Core/Cache/SharedArchive.cpp
+++ b/Core/Cache/SharedArchive.cpp
@@ -33,8 +33,7 @@
 #include "../PrecompiledHeaders.h"
 #include "SharedArchive.h"
 
-
-#include "../Uuid.h"
+#include "../SystemToolbox.h"
 
 
 namespace Orthanc
@@ -100,7 +99,7 @@ namespace Orthanc
       RemoveInternal(oldest);
     }
 
-    std::string id = Toolbox::GenerateUuid();
+    std::string id = SystemToolbox::GenerateUuid();
     RemoveInternal(id);  // Should never be useful because of UUID
     archive_[id] = obj;
     lru_.Add(id);
diff --git a/Core/DicomFormat/DicomArray.h b/Core/DicomFormat/DicomArray.h
index a223685..97a7d9c 100644
--- a/Core/DicomFormat/DicomArray.h
+++ b/Core/DicomFormat/DicomArray.h
@@ -47,7 +47,7 @@ namespace Orthanc
     Elements  elements_;
 
   public:
-    DicomArray(const DicomMap& map);
+    explicit DicomArray(const DicomMap& map);
 
     ~DicomArray();
 
diff --git a/Core/DicomFormat/DicomImageInformation.h b/Core/DicomFormat/DicomImageInformation.h
index 568e6e3..e27db09 100644
--- a/Core/DicomFormat/DicomImageInformation.h
+++ b/Core/DicomFormat/DicomImageInformation.h
@@ -57,7 +57,7 @@ namespace Orthanc
     PhotometricInterpretation  photometric_;
 
   public:
-    DicomImageInformation(const DicomMap& values);
+    explicit DicomImageInformation(const DicomMap& values);
 
     unsigned int GetWidth() const
     {
diff --git a/Core/DicomFormat/DicomMap.h b/Core/DicomFormat/DicomMap.h
index 58e50b8..160363f 100644
--- a/Core/DicomFormat/DicomMap.h
+++ b/Core/DicomFormat/DicomMap.h
@@ -47,7 +47,7 @@ namespace Orthanc
   private:
     friend class DicomArray;
     friend class FromDcmtkBridge;
-    friend class ToDcmtkBridge;
+    friend class ParsedDicomFile;
 
     typedef std::map<DicomTag, DicomValue*>  Map;
 
diff --git a/Core/DicomFormat/DicomTag.h b/Core/DicomFormat/DicomTag.h
index 25f4259..bf971ca 100644
--- a/Core/DicomFormat/DicomTag.h
+++ b/Core/DicomFormat/DicomTag.h
@@ -100,6 +100,7 @@ namespace Orthanc
   static const DicomTag DICOM_TAG_SERIES_INSTANCE_UID(0x0020, 0x000e);
   static const DicomTag DICOM_TAG_STUDY_INSTANCE_UID(0x0020, 0x000d);
   static const DicomTag DICOM_TAG_PIXEL_DATA(0x7fe0, 0x0010);
+  static const DicomTag DICOM_TAG_TRANSFER_SYNTAX_UID(0x0002, 0x0010);
 
   static const DicomTag DICOM_TAG_IMAGE_INDEX(0x0054, 0x1330);
   static const DicomTag DICOM_TAG_INSTANCE_NUMBER(0x0020, 0x0013);
@@ -127,6 +128,7 @@ namespace Orthanc
   static const DicomTag DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER(0x0020, 0x0100);
 
   // Tags for C-FIND and C-MOVE
+  static const DicomTag DICOM_TAG_MESSAGE_ID(0x0000, 0x0110);
   static const DicomTag DICOM_TAG_SPECIFIC_CHARACTER_SET(0x0008, 0x0005);
   static const DicomTag DICOM_TAG_QUERY_RETRIEVE_LEVEL(0x0008, 0x0052);
   static const DicomTag DICOM_TAG_MODALITIES_IN_STUDY(0x0008, 0x0061);
diff --git a/Core/DicomFormat/DicomValue.cpp b/Core/DicomFormat/DicomValue.cpp
index 32a17b5..2a4c2f2 100644
--- a/Core/DicomFormat/DicomValue.cpp
+++ b/Core/DicomFormat/DicomValue.cpp
@@ -81,7 +81,7 @@ namespace Orthanc
   }
 
   
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
   void DicomValue::FormatDataUriScheme(std::string& target,
                                        const std::string& mime) const
   {
diff --git a/Core/DicomFormat/DicomValue.h b/Core/DicomFormat/DicomValue.h
index ad0ec54..c4844b7 100644
--- a/Core/DicomFormat/DicomValue.h
+++ b/Core/DicomFormat/DicomValue.h
@@ -35,6 +35,11 @@
 #include <string>
 #include <boost/noncopyable.hpp>
 
+#if !defined(ORTHANC_ENABLE_BASE64)
+#  error The macro ORTHANC_ENABLE_BASE64 must be defined
+#endif
+
+
 namespace Orthanc
 {
   class DicomValue : public boost::noncopyable
@@ -78,7 +83,7 @@ namespace Orthanc
     
     DicomValue* Clone() const;
 
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
     void FormatDataUriScheme(std::string& target,
                              const std::string& mime) const;
 
diff --git a/Core/Enumerations.cpp b/Core/Enumerations.cpp
index e600828..19057b4 100644
--- a/Core/Enumerations.cpp
+++ b/Core/Enumerations.cpp
@@ -64,7 +64,7 @@ namespace Orthanc
         return "Parameter out of range";
 
       case ErrorCode_NotEnoughMemory:
-        return "Not enough memory";
+        return "The server hosting Orthanc is running out of memory";
 
       case ErrorCode_BadParameterType:
         return "Bad type for a parameter";
@@ -156,6 +156,9 @@ namespace Orthanc
       case ErrorCode_NotAcceptable:
         return "Cannot send a response which is acceptable according to the Accept HTTP header";
 
+      case ErrorCode_NullPointer:
+        return "Cannot handle a NULL pointer";
+
       case ErrorCode_SQLiteNotOpened:
         return "SQLite: The database is not opened";
 
@@ -733,6 +736,9 @@ namespace Orthanc
       case PixelFormat_RGBA32:
         return "RGBA32";
 
+      case PixelFormat_BGRA32:
+        return "BGRA32";
+
       case PixelFormat_Grayscale8:
         return "Grayscale (unsigned 8bpp)";
 
@@ -1061,6 +1067,7 @@ namespace Orthanc
         return 3;
 
       case PixelFormat_RGBA32:
+      case PixelFormat_BGRA32:
         return 4;
 
       case PixelFormat_Float32:
@@ -1076,15 +1083,18 @@ namespace Orthanc
   bool GetDicomEncoding(Encoding& encoding,
                         const char* specificCharacterSet)
   {
-    std::string s = specificCharacterSet;
+    std::string s = Toolbox::StripSpaces(specificCharacterSet);
     Toolbox::ToUpperCase(s);
 
     // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2
     // https://github.com/dcm4che/dcm4che/blob/master/dcm4che-core/src/main/java/org/dcm4che3/data/SpecificCharacterSet.java
     if (s == "ISO_IR 6" ||
-        s == "ISO_IR 192" ||
         s == "ISO 2022 IR 6")
     {
+      encoding = Encoding_Ascii;
+    }
+    else if (s == "ISO_IR 192")
+    {
       encoding = Encoding_Utf8;
     }
     else if (s == "ISO_IR 100" ||
@@ -1231,8 +1241,10 @@ namespace Orthanc
     // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2
     switch (encoding)
     {
-      case Encoding_Utf8:
       case Encoding_Ascii:
+        return "ISO_IR 6";
+
+      case Encoding_Utf8:
         return "ISO_IR 192";
 
       case Encoding_Latin1:
diff --git a/Core/Enumerations.h b/Core/Enumerations.h
index 7eef119..9b18661 100644
--- a/Core/Enumerations.h
+++ b/Core/Enumerations.h
@@ -52,7 +52,7 @@ namespace Orthanc
     ErrorCode_Plugin = 1    /*!< Error encountered within the plugin engine */,
     ErrorCode_NotImplemented = 2    /*!< Not implemented yet */,
     ErrorCode_ParameterOutOfRange = 3    /*!< Parameter out of range */,
-    ErrorCode_NotEnoughMemory = 4    /*!< Not enough memory */,
+    ErrorCode_NotEnoughMemory = 4    /*!< The server hosting Orthanc is running out of memory */,
     ErrorCode_BadParameterType = 5    /*!< Bad type for a parameter */,
     ErrorCode_BadSequenceOfCalls = 6    /*!< Bad sequence of calls */,
     ErrorCode_InexistentItem = 7    /*!< Accessing an inexistent item */,
@@ -83,6 +83,7 @@ namespace Orthanc
     ErrorCode_StorageAreaPlugin = 32    /*!< Error in the plugin implementing a custom storage area */,
     ErrorCode_EmptyRequest = 33    /*!< The request is empty */,
     ErrorCode_NotAcceptable = 34    /*!< Cannot send a response which is acceptable according to the Accept HTTP header */,
+    ErrorCode_NullPointer = 35    /*!< Cannot handle a NULL pointer */,
     ErrorCode_SQLiteNotOpened = 1000    /*!< SQLite: The database is not opened */,
     ErrorCode_SQLiteAlreadyOpened = 1001    /*!< SQLite: Connection is already open */,
     ErrorCode_SQLiteCannotOpen = 1002    /*!< SQLite: Unable to open the database */,
@@ -195,7 +196,10 @@ namespace Orthanc
      * {summary}{Graylevel, floating-point image.}
      * {description}{The image is graylevel. Each pixel is floating-point and stored in 4 bytes.}
      **/
-    PixelFormat_Float32 = 6
+    PixelFormat_Float32 = 6,
+
+    // This is the memory layout for Cairo
+    PixelFormat_BGRA32 = 7
   };
 
 
diff --git a/Core/FileStorage/FilesystemStorage.cpp b/Core/FileStorage/FilesystemStorage.cpp
index e282065..668ab20 100644
--- a/Core/FileStorage/FilesystemStorage.cpp
+++ b/Core/FileStorage/FilesystemStorage.cpp
@@ -39,7 +39,7 @@
 #include "../Logging.h"
 #include "../OrthancException.h"
 #include "../Toolbox.h"
-#include "../Uuid.h"
+#include "../SystemToolbox.h"
 
 #include <boost/filesystem/fstream.hpp>
 
@@ -83,14 +83,40 @@ namespace Orthanc
     //root_ = boost::filesystem::absolute(root).string();
     root_ = root;
 
-    Toolbox::MakeDirectory(root);
+    SystemToolbox::MakeDirectory(root);
   }
 
+
+
+  static const char* GetDescriptionInternal(FileContentType content)
+  {
+    // This function is for logging only (internal use), a more
+    // fully-featured version is available in ServerEnumerations.cpp
+    switch (content)
+    {
+      case FileContentType_Unknown:
+        return "Unknown";
+
+      case FileContentType_Dicom:
+        return "DICOM";
+
+      case FileContentType_DicomAsJson:
+        return "JSON summary of DICOM";
+
+      default:
+        return "User-defined";
+    }
+  }
+
+
   void FilesystemStorage::Create(const std::string& uuid,
                                  const void* content, 
                                  size_t size,
-                                 FileContentType /*type*/)
+                                 FileContentType type)
   {
+    LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) 
+              << "\" type (size: " << (size / (1024 * 1024) + 1) << "MB)";
+
     boost::filesystem::path path;
     
     path = GetPath(uuid);
@@ -117,33 +143,19 @@ namespace Orthanc
       }
     }
 
-    boost::filesystem::ofstream f;
-    f.open(path, std::ofstream::out | std::ios::binary);
-    if (!f.good())
-    {
-      throw OrthancException(ErrorCode_FileStorageCannotWrite);
-    }
-
-    if (size != 0)
-    {
-      f.write(static_cast<const char*>(content), size);
-      if (!f.good())
-      {
-        f.close();
-        throw OrthancException(ErrorCode_FileStorageCannotWrite);
-      }
-    }
-
-    f.close();
+    SystemToolbox::WriteFile(content, size, path.string());
   }
 
 
   void FilesystemStorage::Read(std::string& content,
                                const std::string& uuid,
-                               FileContentType /*type*/)
+                               FileContentType type)
   {
+    LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) 
+              << "\" content type";
+
     content.clear();
-    Toolbox::ReadFile(content, GetPath(uuid).string());
+    SystemToolbox::ReadFile(content, GetPath(uuid).string());
   }
 
 
@@ -165,7 +177,7 @@ namespace Orthanc
     {
       for (fs::recursive_directory_iterator current(root_), end; current != end ; ++current)
       {
-        if (Toolbox::IsRegularFile(current->path().string()))
+        if (SystemToolbox::IsRegularFile(current->path().string()))
         {
           try
           {
@@ -211,11 +223,9 @@ namespace Orthanc
 
 
   void FilesystemStorage::Remove(const std::string& uuid,
-                                 FileContentType /*type*/)
+                                 FileContentType type)
   {
-#if ORTHANC_ENABLE_GOOGLE_LOG == 1
-    LOG(INFO) << "Deleting file " << uuid;
-#endif
+    LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast<int>(type);
 
     namespace fs = boost::filesystem;
 
diff --git a/Core/FileStorage/FilesystemStorage.h b/Core/FileStorage/FilesystemStorage.h
index d003bc5..a7f52cf 100644
--- a/Core/FileStorage/FilesystemStorage.h
+++ b/Core/FileStorage/FilesystemStorage.h
@@ -52,7 +52,7 @@ namespace Orthanc
     boost::filesystem::path GetPath(const std::string& uuid) const;
 
   public:
-    FilesystemStorage(std::string root);
+    explicit FilesystemStorage(std::string root);
 
     virtual void Create(const std::string& uuid,
                         const void* content, 
diff --git a/Core/FileStorage/StorageAccessor.cpp b/Core/FileStorage/StorageAccessor.cpp
index a202d60..d3342dd 100644
--- a/Core/FileStorage/StorageAccessor.cpp
+++ b/Core/FileStorage/StorageAccessor.cpp
@@ -36,6 +36,8 @@
 #include "../Compression/ZlibCompressor.h"
 #include "../OrthancException.h"
 #include "../HttpServer/HttpStreamTranscoder.h"
+#include "../Toolbox.h"
+#include "../SystemToolbox.h"
 
 namespace Orthanc
 {
@@ -45,7 +47,7 @@ namespace Orthanc
                                   CompressionType compression,
                                   bool storeMd5)
   {
-    std::string uuid = Toolbox::GenerateUuid();
+    std::string uuid = SystemToolbox::GenerateUuid();
 
     std::string md5;
 
diff --git a/Core/HttpClient.cpp b/Core/HttpClient.cpp
index 1c98f8e..70392ff 100644
--- a/Core/HttpClient.cpp
+++ b/Core/HttpClient.cpp
@@ -37,6 +37,7 @@
 #include "OrthancException.h"
 #include "Logging.h"
 #include "ChunkedBuffer.h"
+#include "SystemToolbox.h"
 
 #include <string.h>
 #include <curl/curl.h>
@@ -44,7 +45,17 @@
 #include <boost/thread/mutex.hpp>
 
 
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
+// For OpenSSL initialization and finalization
+#  include <openssl/conf.h>
+#  include <openssl/engine.h>
+#  include <openssl/err.h>
+#  include <openssl/evp.h>
+#  include <openssl/ssl.h>
+#endif
+
+
+#if ORTHANC_ENABLE_PKCS11 == 1
 #  include "Pkcs11.h"
 #endif
 
@@ -151,7 +162,7 @@ namespace Orthanc
       return timeout_;
     }
 
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
     bool IsPkcs11Initialized()
     {
       boost::mutex::scoped_lock lock(mutex_);
@@ -307,10 +318,10 @@ namespace Orthanc
     url_ = "";
     method_ = HttpMethod_Get;
     lastStatus_ = HttpStatus_200_Ok;
-    isVerbose_ = false;
+    SetVerbose(false);
     timeout_ = GlobalParameters::GetInstance().GetDefaultTimeout();
     GlobalParameters::GetInstance().GetDefaultProxy(proxy_);
-    GlobalParameters::GetInstance().GetSslConfiguration(verifyPeers_, caCertificates_);
+    GlobalParameters::GetInstance().GetSslConfiguration(verifyPeers_, caCertificates_);    
   }
 
 
@@ -318,7 +329,8 @@ namespace Orthanc
     pimpl_(new PImpl), 
     verifyPeers_(true),
     pkcs11Enabled_(false),
-    headersToLowerCase_(true)
+    headersToLowerCase_(true),
+    redirectionFollowed_(true)
   {
     Setup();
   }
@@ -328,7 +340,8 @@ namespace Orthanc
                          const std::string& uri) : 
     pimpl_(new PImpl), 
     verifyPeers_(true),
-    headersToLowerCase_(true)
+    headersToLowerCase_(true),
+    redirectionFollowed_(true)
   {
     Setup();
 
@@ -423,7 +436,7 @@ namespace Orthanc
       CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADERDATA, &headerParameters));
     }
 
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
     // Setup HTTPS-related options
 
     if (verifyPeers_)
@@ -449,7 +462,7 @@ namespace Orthanc
 
     if (pkcs11Enabled_)
     {
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
       if (GlobalParameters::GetInstance().IsPkcs11Initialized())
       {
         CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLENGINE, Pkcs11::GetEngineIdentifier()));
@@ -468,7 +481,7 @@ namespace Orthanc
     }
     else if (!clientCertificateFile_.empty())
     {
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
       CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERTTYPE, "PEM"));
       CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERT, clientCertificateFile_.c_str()));
 
@@ -497,9 +510,18 @@ namespace Orthanc
     CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_NOBODY, 0L));
     CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, NULL));
     CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, NULL));
-    CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, 0));
+    CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, 0L));
     CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PROXY, NULL));
 
+    if (redirectionFollowed_)
+    {
+      CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 1L));
+    }
+    else
+    {
+      CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 0L));
+    }
+
     // Set timeouts
     if (timeout_ <= 0)
     {
@@ -650,7 +672,7 @@ namespace Orthanc
   void HttpClient::ConfigureSsl(bool httpsVerifyPeers,
                                 const std::string& httpsVerifyCertificates)
   {
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
     if (httpsVerifyPeers)
     {
       if (httpsVerifyCertificates.empty())
@@ -675,13 +697,11 @@ namespace Orthanc
   
   void HttpClient::GlobalInitialize()
   {
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
     CheckCode(curl_global_init(CURL_GLOBAL_ALL));
 #else
     CheckCode(curl_global_init(CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL));
 #endif
-
-    CheckCode(curl_global_init(CURL_GLOBAL_DEFAULT));
   }
 
 
@@ -689,7 +709,7 @@ namespace Orthanc
   {
     curl_global_cleanup();
 
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
     Pkcs11::Finalize();
 #endif
   }
@@ -754,14 +774,14 @@ namespace Orthanc
       throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
 
-    if (!Toolbox::IsRegularFile(certificateFile))
+    if (!SystemToolbox::IsRegularFile(certificateFile))
     {
       LOG(ERROR) << "Cannot open certificate file: " << certificateFile;
       throw OrthancException(ErrorCode_InexistentFile);
     }
 
     if (!certificateKeyFile.empty() && 
-        !Toolbox::IsRegularFile(certificateKeyFile))
+        !SystemToolbox::IsRegularFile(certificateKeyFile))
     {
       LOG(ERROR) << "Cannot open key file: " << certificateKeyFile;
       throw OrthancException(ErrorCode_InexistentFile);
@@ -777,7 +797,7 @@ namespace Orthanc
                                     const std::string& pin,
                                     bool verbose)
   {
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
     LOG(INFO) << "Initializing PKCS#11 using " << module 
               << (pin.empty() ? " (no PIN provided)" : " (PIN is provided)");
     GlobalParameters::GetInstance().InitializePkcs11(module, pin, verbose);    
@@ -786,4 +806,32 @@ namespace Orthanc
     throw OrthancException(ErrorCode_InternalError);
 #endif
   }
+
+
+  void HttpClient::InitializeOpenSsl()
+  {
+#if ORTHANC_ENABLE_SSL == 1
+    // https://wiki.openssl.org/index.php/Library_Initialization
+    SSL_library_init();
+    SSL_load_error_strings();
+    OpenSSL_add_all_algorithms();
+    ERR_load_crypto_strings();
+#endif
+  }
+
+
+  void HttpClient::FinalizeOpenSsl()
+  {
+ #if ORTHANC_ENABLE_SSL == 1
+    // Finalize OpenSSL
+    // https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
+    FIPS_mode_set(0);
+    ENGINE_cleanup();
+    CONF_modules_unload(1);
+    EVP_cleanup();
+    CRYPTO_cleanup_all_ex_data();
+    ERR_remove_state(0);
+    ERR_free_strings();
+#endif
+  }
 }
diff --git a/Core/HttpClient.h b/Core/HttpClient.h
index 2576644..1b80f33 100644
--- a/Core/HttpClient.h
+++ b/Core/HttpClient.h
@@ -39,6 +39,15 @@
 #include <boost/shared_ptr.hpp>
 #include <json/json.h>
 
+#if !defined(ORTHANC_ENABLE_SSL)
+#  error The macro ORTHANC_ENABLE_SSL must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_PKCS11)
+#  error The macro ORTHANC_ENABLE_PKCS11 must be defined
+#endif
+
+
 namespace Orthanc
 {
   class HttpClient
@@ -67,6 +76,7 @@ namespace Orthanc
     std::string clientCertificateKeyPassword_;
     bool pkcs11Enabled_;
     bool headersToLowerCase_;
+    bool redirectionFollowed_;
 
     void Setup();
 
@@ -243,10 +253,24 @@ namespace Orthanc
       return headersToLowerCase_;
     }
 
+    void SetRedirectionFollowed(bool follow)
+    {
+      redirectionFollowed_ = follow;
+    }
+
+    bool IsRedirectionFollowed() const
+    {
+      return redirectionFollowed_;
+    }
+
     static void GlobalInitialize();
   
     static void GlobalFinalize();
 
+    static void InitializeOpenSsl();
+
+    static void FinalizeOpenSsl();
+
     static void InitializePkcs11(const std::string& module,
                                  const std::string& pin,
                                  bool verbose);
diff --git a/Core/HttpServer/FilesystemHttpHandler.cpp b/Core/HttpServer/FilesystemHttpHandler.cpp
index 84fe5cf..33909f3 100644
--- a/Core/HttpServer/FilesystemHttpHandler.cpp
+++ b/Core/HttpServer/FilesystemHttpHandler.cpp
@@ -34,6 +34,7 @@
 #include "FilesystemHttpHandler.h"
 
 #include "../OrthancException.h"
+#include "../SystemToolbox.h"
 #include "FilesystemHttpSender.h"
 
 #include <boost/filesystem.hpp>
@@ -95,7 +96,7 @@ namespace Orthanc
 #endif
 
       std::string h = Toolbox::FlattenUri(uri) + "/" + f;
-      if (Toolbox::IsRegularFile(it->path().string()))
+      if (SystemToolbox::IsRegularFile(it->path().string()))
       {
         s += "<li><a href=\"" + h + "\">" + f + "</a></li>";
       }
@@ -158,7 +159,7 @@ namespace Orthanc
       p /= uri[i];
     }
 
-    if (Toolbox::IsRegularFile(p.string()))
+    if (SystemToolbox::IsRegularFile(p.string()))
     {
       FilesystemHttpSender sender(p);
       output.Answer(sender);   // TODO COMPRESSION
diff --git a/Core/HttpServer/FilesystemHttpSender.h b/Core/HttpServer/FilesystemHttpSender.h
index 367835f..8e09595 100644
--- a/Core/HttpServer/FilesystemHttpSender.h
+++ b/Core/HttpServer/FilesystemHttpSender.h
@@ -50,12 +50,12 @@ namespace Orthanc
     void Initialize(const boost::filesystem::path& path);
 
   public:
-    FilesystemHttpSender(const std::string& path)
+    explicit FilesystemHttpSender(const std::string& path)
     {
       Initialize(path);
     }
 
-    FilesystemHttpSender(const boost::filesystem::path& path)
+    explicit FilesystemHttpSender(const boost::filesystem::path& path)
     {
       Initialize(path);
     }
diff --git a/Core/HttpServer/HttpOutput.cpp b/Core/HttpServer/HttpOutput.cpp
index 7e6bc34..3e0862e 100644
--- a/Core/HttpServer/HttpOutput.cpp
+++ b/Core/HttpServer/HttpOutput.cpp
@@ -35,6 +35,7 @@
 
 #include "../Logging.h"
 #include "../OrthancException.h"
+#include "../SystemToolbox.h"
 #include "../Toolbox.h"
 #include "../Compression/GzipCompressor.h"
 #include "../Compression/ZlibCompressor.h"
@@ -438,7 +439,7 @@ namespace Orthanc
       header += *it;
     }
 
-    multipartBoundary_ = Toolbox::GenerateUuid();
+    multipartBoundary_ = SystemToolbox::GenerateUuid();
     multipartContentType_ = contentType;
     header += "Content-Type: multipart/" + subType + "; type=" + contentType + "; boundary=" + multipartBoundary_ + "\r\n\r\n";
 
diff --git a/Core/HttpServer/HttpOutput.h b/Core/HttpServer/HttpOutput.h
index ea0e889..ff08bf1 100644
--- a/Core/HttpServer/HttpOutput.h
+++ b/Core/HttpServer/HttpOutput.h
@@ -32,13 +32,14 @@
 
 #pragma once
 
-#include <list>
-#include <string>
-#include <stdint.h>
 #include "../Enumerations.h"
 #include "IHttpOutputStream.h"
 #include "IHttpStreamAnswer.h"
-#include "../Uuid.h"
+
+#include <list>
+#include <string>
+#include <stdint.h>
+#include <map>
 
 namespace Orthanc
 {
diff --git a/Core/HttpServer/HttpStreamTranscoder.h b/Core/HttpServer/HttpStreamTranscoder.h
index 6afe583..0647eda 100644
--- a/Core/HttpServer/HttpStreamTranscoder.h
+++ b/Core/HttpServer/HttpStreamTranscoder.h
@@ -61,6 +61,7 @@ namespace Orthanc
       sourceCompression_(compression),
       bytesToSkip_(0),
       skipped_(0),
+      currentChunkOffset_(0),
       ready_(false)
     {
     }
diff --git a/Core/HttpServer/IHttpHandler.h b/Core/HttpServer/IHttpHandler.h
index f99cbb5..0bc7f55 100644
--- a/Core/HttpServer/IHttpHandler.h
+++ b/Core/HttpServer/IHttpHandler.h
@@ -32,7 +32,7 @@
 
 #pragma once
 
-#include "../Enumerations.h"
+#include "../Toolbox.h"
 #include "HttpOutput.h"
 
 #include <map>
diff --git a/Core/HttpServer/MongooseServer.cpp b/Core/HttpServer/MongooseServer.cpp
index 8270e76..01b7a55 100644
--- a/Core/HttpServer/MongooseServer.cpp
+++ b/Core/HttpServer/MongooseServer.cpp
@@ -49,7 +49,11 @@
 #include <stdio.h>
 #include <boost/thread.hpp>
 
-#if ORTHANC_SSL_ENABLED == 1
+#if !defined(ORTHANC_ENABLE_SSL)
+#  error The macro ORTHANC_ENABLE_SSL must be defined
+#endif
+
+#if ORTHANC_ENABLE_SSL == 1
 #include <openssl/opensslv.h>
 #endif
 
@@ -575,16 +579,14 @@ namespace Orthanc
   }
 
 
-  static void InternalCallback(struct mg_connection *connection,
+  static void InternalCallback(HttpOutput& output /* out */,
+                               HttpMethod& method /* out */,
+                               MongooseServer& server,
+                               struct mg_connection *connection,
                                const struct mg_request_info *request)
   {
-    MongooseServer* that = reinterpret_cast<MongooseServer*>(request->user_data);
-
-    MongooseOutputStream stream(connection);
-    HttpOutput output(stream, that->IsKeepAliveEnabled());
-
     // Check remote calls
-    if (!that->IsRemoteAccessAllowed() &&
+    if (!server.IsRemoteAccessAllowed() &&
         request->remote_ip != LOCALHOST)
     {
       output.SendUnauthorized(ORTHANC_REALM);
@@ -604,7 +606,7 @@ namespace Orthanc
       VLOG(1) << "HTTP header: [" << name << "]: [" << value << "]";
     }
 
-    if (that->IsHttpCompressionEnabled())
+    if (server.IsHttpCompressionEnabled())
     {
       ConfigureHttpCompression(output, headers);
     }
@@ -619,7 +621,7 @@ namespace Orthanc
 
 
     // Compute the HTTP method, taking method faking into consideration
-    HttpMethod method = HttpMethod_Get;
+    method = HttpMethod_Get;
     if (!ExtractMethod(method, request, headers, argumentsGET))
     {
       output.SendStatus(HttpStatus_400_BadRequest);
@@ -628,7 +630,8 @@ namespace Orthanc
 
 
     // Authenticate this connection
-    if (that->IsAuthenticationEnabled() && !IsAccessGranted(*that, headers))
+    if (server.IsAuthenticationEnabled() && 
+        !IsAccessGranted(server, headers))
     {
       output.SendUnauthorized(ORTHANC_REALM);
       return;
@@ -645,7 +648,7 @@ namespace Orthanc
 
     std::string username = GetAuthenticatedUsername(headers);
 
-    const IIncomingHttpRequestFilter *filter = that->GetIncomingHttpRequestFilter();
+    const IIncomingHttpRequestFilter *filter = server.GetIncomingHttpRequestFilter();
     if (filter != NULL)
     {
       if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str(), headers))
@@ -679,7 +682,7 @@ namespace Orthanc
         if (contentType.size() >= multipartLength &&
             !memcmp(contentType.c_str(), multipart, multipartLength))
         {
-          status = ParseMultipartPost(body, connection, headers, contentType, that->GetChunkStore());
+          status = ParseMultipartPost(body, connection, headers, contentType, server.GetChunkStore());
         }
         else
         {
@@ -713,7 +716,7 @@ namespace Orthanc
     {
       Toolbox::SplitUriComponents(uri, request->uri);
     }
-    catch (OrthancException)
+    catch (OrthancException&)
     {
       output.SendStatus(HttpStatus_400_BadRequest);
       return;
@@ -722,56 +725,100 @@ namespace Orthanc
 
     LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri);
 
+    bool found = false;
+
+    if (server.HasHandler())
+    {
+      found = server.GetHandler().Handle(output, RequestOrigin_RestApi, remoteIp, username.c_str(), 
+                                         method, uri, headers, argumentsGET, body.c_str(), body.size());
+    }
+
+    if (!found)
+    {
+      throw OrthancException(ErrorCode_UnknownResource);
+    }
+  }
+
 
+  static void ProtectedCallback(struct mg_connection *connection,
+                                const struct mg_request_info *request)
+  {
     try
     {
-      bool found = false;
+      MongooseServer* server = reinterpret_cast<MongooseServer*>(request->user_data);
+      
+      if (server == NULL)
+      {
+        MongooseOutputStream stream(connection);
+        HttpOutput output(stream, false /* assume no keep-alive */);
+        output.SendStatus(HttpStatus_500_InternalServerError);
+        return;
+      }
+      
+      MongooseOutputStream stream(connection);
+      HttpOutput output(stream, server->IsKeepAliveEnabled());
+      HttpMethod method = HttpMethod_Get;
 
       try
       {
-        if (that->HasHandler())
+        try
         {
-          found = that->GetHandler().Handle(output, RequestOrigin_RestApi, remoteIp, username.c_str(), 
-                                            method, uri, headers, argumentsGET, body.c_str(), body.size());
+          InternalCallback(output, method, *server, connection, request);
+        }
+        catch (OrthancException&)
+        {
+          throw;  // Pass the exception to the main handler below
+        }
+        // Now convert native exceptions as OrthancException
+        catch (boost::bad_lexical_cast&)
+        {
+          LOG(ERROR) << "Syntax error in some user-supplied data";
+          throw OrthancException(ErrorCode_BadParameterType);
+        }
+        catch (std::runtime_error&)
+        {
+          // Presumably an error while parsing the JSON body
+          throw OrthancException(ErrorCode_BadRequest);
+        }
+        catch (std::bad_alloc&)
+        {
+          LOG(ERROR) << "The server hosting Orthanc is running out of memory";
+          throw OrthancException(ErrorCode_NotEnoughMemory);
+        }
+        catch (...)
+        {
+          LOG(ERROR) << "An unhandled exception was generated inside the HTTP server";
+          throw OrthancException(ErrorCode_InternalError);
         }
       }
-      catch (boost::bad_lexical_cast&)
-      {
-        throw OrthancException(ErrorCode_BadParameterType);
-      }
-      catch (std::runtime_error&)
+      catch (OrthancException& e)
       {
-        // Presumably an error while parsing the JSON body
-        throw OrthancException(ErrorCode_BadRequest);
-      }
+        assert(server != NULL);
 
-      if (!found)
-      {
-        throw OrthancException(ErrorCode_UnknownResource);
-      }
-    }
-    catch (OrthancException& e)
-    {
-      // Using this candidate handler results in an exception
-      try
-      {
-        if (that->GetExceptionFormatter() == NULL)
+        // Using this candidate handler results in an exception
+        try
         {
-          LOG(ERROR) << "Exception in the HTTP handler: " << e.What();
-          output.SendStatus(e.GetHttpStatus());
+          if (server->GetExceptionFormatter() == NULL)
+          {
+            LOG(ERROR) << "Exception in the HTTP handler: " << e.What();
+            output.SendStatus(e.GetHttpStatus());
+          }
+          else
+          {
+            server->GetExceptionFormatter()->Format(output, e, method, request->uri);
+          }
         }
-        else
+        catch (OrthancException&)
         {
-          that->GetExceptionFormatter()->Format(output, e, method, request->uri);
+          // An exception here reflects the fact that the status code
+          // was already set by the HTTP handler.
         }
       }
-      catch (OrthancException&)
-      {
-        // An exception here reflects the fact that the status code
-        // was already set by the HTTP handler.
-      }
-
-      return;
+    }
+    catch (...)
+    {
+      // We should never arrive at this point, where it is even impossible to send an answer
+      LOG(ERROR) << "Catastrophic error inside the HTTP server, giving up";
     }
   }
 
@@ -783,7 +830,7 @@ namespace Orthanc
   {
     if (event == MG_NEW_REQUEST) 
     {
-      InternalCallback(connection, request);
+      ProtectedCallback(connection, request);
 
       // Mark as processed
       return (void*) "";
@@ -799,7 +846,7 @@ namespace Orthanc
   {
     struct mg_request_info *request = mg_get_request_info(connection);
 
-    InternalCallback(connection, request);
+    ProtectedCallback(connection, request);
 
     return 1;  // Do not let Mongoose handle the request by itself
   }
@@ -831,7 +878,7 @@ namespace Orthanc
     httpCompression_ = true;
     exceptionFormatter_ = NULL;
 
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
     // Check for the Heartbleed exploit
     // https://en.wikipedia.org/wiki/OpenSSL#Heartbleed_bug
     if (OPENSSL_VERSION_NUMBER <  0x1000107fL  /* openssl-1.0.1g */ &&
@@ -932,7 +979,7 @@ namespace Orthanc
   {
     Stop();
 
-#if ORTHANC_SSL_ENABLED == 0
+#if ORTHANC_ENABLE_SSL == 0
     if (enabled)
     {
       throw OrthancException(ErrorCode_SslDisabled);
@@ -951,7 +998,7 @@ namespace Orthanc
   {
     Stop();
     keepAlive_ = enabled;
-    LOG(WARNING) << "HTTP keep alive is " << (enabled ? "enabled" : "disabled");
+    LOG(INFO) << "HTTP keep alive is " << (enabled ? "enabled" : "disabled");
   }
 
 
diff --git a/Core/Images/Font.cpp b/Core/Images/Font.cpp
index 5253ea2..873d690 100644
--- a/Core/Images/Font.cpp
+++ b/Core/Images/Font.cpp
@@ -33,6 +33,7 @@
 #include "../PrecompiledHeaders.h"
 #include "Font.h"
 
+#include "../SystemToolbox.h"
 #include "../Toolbox.h"
 #include "../OrthancException.h"
 
@@ -135,7 +136,7 @@ namespace Orthanc
   void Font::LoadFromFile(const std::string& path)
   {
     std::string font;
-    Toolbox::ReadFile(font, path);
+    SystemToolbox::ReadFile(font, path);
     LoadFromMemory(font);
   }
 
diff --git a/Core/Pkcs11.h b/Core/Images/IImageWriter.cpp
similarity index 71%
copy from Core/Pkcs11.h
copy to Core/Images/IImageWriter.cpp
index 3a56c74..b215080 100644
--- a/Core/Pkcs11.h
+++ b/Core/Images/IImageWriter.cpp
@@ -30,27 +30,25 @@
  **/
 
 
-#pragma once
+#include "IImageWriter.h"
 
-#if ORTHANC_PKCS11_ENABLED != 1 || ORTHANC_SSL_ENABLED != 1
-#  error This file cannot be used if OpenSSL or PKCS#11 support is disabled
+#if ORTHANC_SANDBOXED == 0
+#  include "../SystemToolbox.h"
 #endif
 
-
-#include <string>
-
 namespace Orthanc
 {
-  namespace Pkcs11
+#if ORTHANC_SANDBOXED == 0
+  void IImageWriter::WriteToFileInternal(const std::string& path,
+                                         unsigned int width,
+                                         unsigned int height,
+                                         unsigned int pitch,
+                                         PixelFormat format,
+                                         const void* buffer)
   {
-    const char* GetEngineIdentifier();
-
-    bool IsInitialized();
-
-    void Initialize(const std::string& module,
-                    const std::string& pin,
-                    bool verbose);
-
-    void Finalize();
+    std::string compressed;
+    WriteToMemoryInternal(compressed, width, height, pitch, format, buffer);
+    SystemToolbox::WriteFile(compressed, path);
   }
+#endif
 }
diff --git a/Core/Images/IImageWriter.h b/Core/Images/IImageWriter.h
index d8c446d..ca27010 100644
--- a/Core/Images/IImageWriter.h
+++ b/Core/Images/IImageWriter.h
@@ -33,10 +33,13 @@
 #pragma once
 
 #include "ImageAccessor.h"
-#include "../Toolbox.h"
 
 #include <boost/noncopyable.hpp>
 
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
 namespace Orthanc
 {
   class IImageWriter : public boost::noncopyable
@@ -49,17 +52,14 @@ namespace Orthanc
                                        PixelFormat format,
                                        const void* buffer) = 0;
 
+#if ORTHANC_SANDBOXED == 0
     virtual void WriteToFileInternal(const std::string& path,
                                      unsigned int width,
                                      unsigned int height,
                                      unsigned int pitch,
                                      PixelFormat format,
-                                     const void* buffer)
-    {
-      std::string compressed;
-      WriteToMemoryInternal(compressed, width, height, pitch, format, buffer);
-      Toolbox::WriteFile(compressed, path);
-    }
+                                     const void* buffer);
+#endif
 
   public:
     virtual ~IImageWriter()
@@ -73,11 +73,13 @@ namespace Orthanc
                             accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
     }
 
+#if ORTHANC_SANDBOXED == 0
     virtual void WriteToFile(const std::string& path,
                              const ImageAccessor& accessor)
     {
       WriteToFileInternal(path, accessor.GetWidth(), accessor.GetHeight(),
                           accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
     }
+#endif
   };
 }
diff --git a/Core/MultiThreading/Semaphore.cpp b/Core/Images/Image.cpp
similarity index 71%
copy from Core/MultiThreading/Semaphore.cpp
copy to Core/Images/Image.cpp
index 4de6cb8..4212f6d 100644
--- a/Core/MultiThreading/Semaphore.cpp
+++ b/Core/Images/Image.cpp
@@ -30,39 +30,29 @@
  **/
 
 
-#include "../PrecompiledHeaders.h"
-#include "Semaphore.h"
+#include "Image.h"
 
-#include "../OrthancException.h"
+#include "ImageProcessing.h"
 
+#include <memory>
 
 namespace Orthanc
 {
-  Semaphore::Semaphore(unsigned int count) : count_(count)
+  Image::Image(PixelFormat format,
+               unsigned int width,
+               unsigned int height,
+               bool forceMinimalPitch) :
+    image_(format, width, height, forceMinimalPitch)
   {
-    if (count == 0)
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
+    ImageAccessor accessor = image_.GetAccessor();
+    AssignWritable(format, width, height, accessor.GetPitch(), accessor.GetBuffer());
   }
 
-  void Semaphore::Release()
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-
-    count_++;
-    condition_.notify_one(); 
-  }
 
-  void Semaphore::Acquire()
+  Image* Image::Clone(const ImageAccessor& source)
   {
-    boost::mutex::scoped_lock lock(mutex_);
-
-    while (count_ == 0)
-    {
-      condition_.wait(lock);
-    }
-
-    count_++;
+    std::auto_ptr<Image> target(new Image(source.GetFormat(), source.GetWidth(), source.GetHeight(), false));
+    ImageProcessing::Copy(*target, source);
+    return target.release();
   }
 }
diff --git a/Core/Images/Image.h b/Core/Images/Image.h
index 16877f0..eba83c7 100644
--- a/Core/Images/Image.h
+++ b/Core/Images/Image.h
@@ -45,11 +45,9 @@ namespace Orthanc
   public:
     Image(PixelFormat format,
           unsigned int width,
-          unsigned int height) :
-      image_(format, width, height)
-    {
-      ImageAccessor accessor = image_.GetAccessor();
-      AssignWritable(format, width, height, accessor.GetPitch(), accessor.GetBuffer());
-    }
+          unsigned int height,
+          bool forceMinimalPitch);
+
+    static Image* Clone(const ImageAccessor& source);
   };
 }
diff --git a/Core/Images/ImageAccessor.cpp b/Core/Images/ImageAccessor.cpp
index bd7a05a..eff8623 100644
--- a/Core/Images/ImageAccessor.cpp
+++ b/Core/Images/ImageAccessor.cpp
@@ -275,4 +275,22 @@ namespace Orthanc
     return result;
   }
 
+
+  void ImageAccessor::SetFormat(PixelFormat format)
+  {
+    if (readOnly_)
+    {
+#if ORTHANC_ENABLE_LOGGING == 1
+      LOG(ERROR) << "Trying to modify the format of a read-only image";
+#endif
+      throw OrthancException(ErrorCode_ReadOnly);
+    }
+
+    if (::Orthanc::GetBytesPerPixel(format) != ::Orthanc::GetBytesPerPixel(format_))
+    {
+      throw OrthancException(ErrorCode_IncompatibleImageFormat);
+    }
+
+    format_ = format;
+  }
 }
diff --git a/Core/Images/ImageAccessor.h b/Core/Images/ImageAccessor.h
index 02d86d4..77e79c2 100644
--- a/Core/Images/ImageAccessor.h
+++ b/Core/Images/ImageAccessor.h
@@ -125,5 +125,7 @@ namespace Orthanc
                             unsigned int y,
                             unsigned int width,
                             unsigned int height) const;
+
+    void SetFormat(PixelFormat format);
   };
 }
diff --git a/Core/Images/ImageBuffer.cpp b/Core/Images/ImageBuffer.cpp
index a932e47..71364dc 100644
--- a/Core/Images/ImageBuffer.cpp
+++ b/Core/Images/ImageBuffer.cpp
@@ -87,7 +87,9 @@ namespace Orthanc
 
   ImageBuffer::ImageBuffer(PixelFormat format,
                            unsigned int width,
-                           unsigned int height)
+                           unsigned int height,
+                           bool forceMinimalPitch) :
+    forceMinimalPitch_(forceMinimalPitch)
   {
     Initialize();
     SetWidth(width);
@@ -158,16 +160,6 @@ namespace Orthanc
   }
 
 
-  void ImageBuffer::SetMinimalPitchForced(bool force)
-  {
-    if (force != forceMinimalPitch_)
-    {
-      changed_ = true;
-      forceMinimalPitch_ = force;
-    }
-  }
-
-
   void ImageBuffer::AcquireOwnership(ImageBuffer& other)
   {
     // Remove the content of the current image
diff --git a/Core/Images/ImageBuffer.h b/Core/Images/ImageBuffer.h
index 381269e..21b1b15 100644
--- a/Core/Images/ImageBuffer.h
+++ b/Core/Images/ImageBuffer.h
@@ -61,7 +61,8 @@ namespace Orthanc
   public:
     ImageBuffer(PixelFormat format,
                 unsigned int width,
-                unsigned int height);
+                unsigned int height,
+                bool forceMinimalPitch);
 
     ImageBuffer()
     {
@@ -108,8 +109,6 @@ namespace Orthanc
       return forceMinimalPitch_;
     }
 
-    void SetMinimalPitchForced(bool force);
-
     void AcquireOwnership(ImageBuffer& other);
   };
 }
diff --git a/Core/Images/ImageProcessing.cpp b/Core/Images/ImageProcessing.cpp
index a9405b1..23c9fee 100644
--- a/Core/Images/ImageProcessing.cpp
+++ b/Core/Images/ImageProcessing.cpp
@@ -519,6 +519,27 @@ namespace Orthanc
       return;
     }
 
+    if (target.GetFormat() == PixelFormat_BGRA32 &&
+        source.GetFormat() == PixelFormat_RGB24)
+    {
+      for (unsigned int y = 0; y < source.GetHeight(); y++)
+      {
+        const uint8_t* p = reinterpret_cast<const uint8_t*>(source.GetConstRow(y));
+        uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
+        for (unsigned int x = 0; x < source.GetWidth(); x++)
+        {
+          q[0] = p[2];
+          q[1] = p[1];
+          q[2] = p[0];
+          q[3] = 255;
+          p += 3;
+          q += 4;
+        }
+      }
+
+      return;
+    }
+
     throw OrthancException(ErrorCode_NotImplemented);
   }
 
@@ -552,6 +573,61 @@ namespace Orthanc
   }
 
 
+  void ImageProcessing::Set(ImageAccessor& image,
+                            uint8_t red,
+                            uint8_t green,
+                            uint8_t blue,
+                            uint8_t alpha)
+  {
+    uint8_t p[4];
+    unsigned int size;
+
+    switch (image.GetFormat())
+    {
+      case PixelFormat_RGBA32:
+        p[0] = red;
+        p[1] = green;
+        p[2] = blue;
+        p[3] = alpha;
+        size = 4;
+        break;
+
+      case PixelFormat_BGRA32:
+        p[0] = blue;
+        p[1] = green;
+        p[2] = red;
+        p[3] = alpha;
+        size = 4;
+        break;
+
+      case PixelFormat_RGB24:
+        p[0] = red;
+        p[1] = green;
+        p[2] = blue;
+        size = 3;
+        break;
+
+      default:
+        throw OrthancException(ErrorCode_NotImplemented);
+    }    
+
+    for (unsigned int y = 0; y < image.GetHeight(); y++)
+    {
+      uint8_t* q = reinterpret_cast<uint8_t*>(image.GetRow(y));
+
+      for (unsigned int x = 0; x < image.GetWidth(); x++)
+      {
+        for (unsigned int i = 0; i < size; i++)
+        {
+          q[i] = p[i];
+        }
+
+        q += size;
+      }
+    }
+  }
+
+
   void ImageProcessing::ShiftRight(ImageAccessor& image,
                                    unsigned int shift)
   {
diff --git a/Core/Images/ImageProcessing.h b/Core/Images/ImageProcessing.h
index 9c4ab81..45176b5 100644
--- a/Core/Images/ImageProcessing.h
+++ b/Core/Images/ImageProcessing.h
@@ -50,6 +50,12 @@ namespace Orthanc
     static void Set(ImageAccessor& image,
                     int64_t value);
 
+    static void Set(ImageAccessor& image,
+                    uint8_t red,
+                    uint8_t green,
+                    uint8_t blue,
+                    uint8_t alpha);
+
     static void ShiftRight(ImageAccessor& target,
                            unsigned int shift);
 
diff --git a/Core/Images/JpegReader.cpp b/Core/Images/JpegReader.cpp
index 9ddcb37..9d6ea08 100644
--- a/Core/Images/JpegReader.cpp
+++ b/Core/Images/JpegReader.cpp
@@ -36,7 +36,11 @@
 #include "JpegErrorManager.h"
 #include "../OrthancException.h"
 #include "../Logging.h"
-#include "../Toolbox.h"
+
+#if ORTHANC_SANDBOXED == 0
+#  include "../SystemToolbox.h"
+#endif
+
 
 namespace Orthanc
 {
@@ -94,9 +98,10 @@ namespace Orthanc
   }
 
 
+#if ORTHANC_SANDBOXED == 0
   void JpegReader::ReadFromFile(const std::string& filename)
   {
-    FILE* fp = Toolbox::OpenFile(filename, FileMode_ReadBinary);
+    FILE* fp = SystemToolbox::OpenFile(filename, FileMode_ReadBinary);
     if (!fp)
     {
       throw OrthancException(ErrorCode_InexistentFile);
@@ -112,7 +117,7 @@ namespace Orthanc
     {
       jpeg_destroy_decompress(&cinfo);
       fclose(fp);
-      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
+      LOG(ERROR) << "Error during JPEG decoding: " << jerr.GetMessage();
       throw OrthancException(ErrorCode_InternalError);
     }
 
@@ -135,6 +140,7 @@ namespace Orthanc
     jpeg_destroy_decompress(&cinfo);
     fclose(fp);
   }
+#endif
 
 
   void JpegReader::ReadFromMemory(const void* buffer,
@@ -149,7 +155,7 @@ namespace Orthanc
     if (setjmp(jerr.GetJumpBuffer())) 
     {
       jpeg_destroy_decompress(&cinfo);
-      LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
+      LOG(ERROR) << "Error during JPEG decoding: " << jerr.GetMessage();
       throw OrthancException(ErrorCode_InternalError);
     }
 
diff --git a/Core/Images/JpegReader.h b/Core/Images/JpegReader.h
index 5cb5551..978058c 100644
--- a/Core/Images/JpegReader.h
+++ b/Core/Images/JpegReader.h
@@ -37,6 +37,10 @@
 #include <string>
 #include <boost/noncopyable.hpp>
 
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
 namespace Orthanc
 {
   class JpegReader : 
@@ -47,7 +51,9 @@ namespace Orthanc
     std::string  content_;
 
   public:
+#if ORTHANC_SANDBOXED == 0
     void ReadFromFile(const std::string& filename);
+#endif
 
     void ReadFromMemory(const void* buffer,
                         size_t size);
diff --git a/Core/Images/JpegWriter.cpp b/Core/Images/JpegWriter.cpp
index 86f9d3c..6ce0d63 100644
--- a/Core/Images/JpegWriter.cpp
+++ b/Core/Images/JpegWriter.cpp
@@ -35,9 +35,12 @@
 
 #include "../OrthancException.h"
 #include "../Logging.h"
-
 #include "JpegErrorManager.h"
 
+#if ORTHANC_SANDBOXED == 0
+#  include "../SystemToolbox.h"
+#endif
+
 #include <stdlib.h>
 #include <vector>
 
@@ -102,7 +105,7 @@ namespace Orthanc
 
   void JpegWriter::SetQuality(uint8_t quality)
   {
-    if (quality <= 0 || quality > 100)
+    if (quality == 0 || quality > 100)
     {
       throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
@@ -111,6 +114,7 @@ namespace Orthanc
   }
 
 
+#if ORTHANC_SANDBOXED == 0
   void JpegWriter::WriteToFileInternal(const std::string& filename,
                                        unsigned int width,
                                        unsigned int height,
@@ -118,7 +122,7 @@ namespace Orthanc
                                        PixelFormat format,
                                        const void* buffer)
   {
-    FILE* fp = Toolbox::OpenFile(filename, FileMode_WriteBinary);
+    FILE* fp = SystemToolbox::OpenFile(filename, FileMode_WriteBinary);
     if (fp == NULL)
     {
       throw OrthancException(ErrorCode_CannotWriteFile);
@@ -154,6 +158,7 @@ namespace Orthanc
 
     fclose(fp);
   }
+#endif
 
 
   void JpegWriter::WriteToMemoryInternal(std::string& jpeg,
diff --git a/Core/Images/JpegWriter.h b/Core/Images/JpegWriter.h
index 5d18af3..ffb6098 100644
--- a/Core/Images/JpegWriter.h
+++ b/Core/Images/JpegWriter.h
@@ -46,12 +46,14 @@ namespace Orthanc
                                      PixelFormat format,
                                      const void* buffer);
 
+#if ORTHANC_SANDBOXED == 0
     virtual void WriteToMemoryInternal(std::string& jpeg,
                                        unsigned int width,
                                        unsigned int height,
                                        unsigned int pitch,
                                        PixelFormat format,
                                        const void* buffer);
+#endif
 
   private:
     uint8_t  quality_;
diff --git a/Core/Images/PngReader.cpp b/Core/Images/PngReader.cpp
index b93aee0..8315ca7 100644
--- a/Core/Images/PngReader.cpp
+++ b/Core/Images/PngReader.cpp
@@ -36,11 +36,16 @@
 #include "../OrthancException.h"
 #include "../Toolbox.h"
 
+#if ORTHANC_SANDBOXED == 0
+#  include "../SystemToolbox.h"
+#endif
+
 #include <png.h>
 #include <string.h>  // For memcpy()
 
 namespace Orthanc
 {
+#if ORTHANC_SANDBOXED == 0
   namespace 
   {
     struct FileRabi
@@ -49,7 +54,7 @@ namespace Orthanc
 
       FileRabi(const char* filename)
       {
-        fp_ = Toolbox::OpenFile(filename, FileMode_ReadBinary);
+        fp_ = SystemToolbox::OpenFile(filename, FileMode_ReadBinary);
         if (!fp_)
         {
           throw OrthancException(ErrorCode_InexistentFile);
@@ -65,6 +70,7 @@ namespace Orthanc
       }
     };
   }
+#endif
 
 
   struct PngReader::PngRabi
@@ -206,6 +212,8 @@ namespace Orthanc
     AssignWritable(format, width, height, pitch, &data_[0]);
   }
 
+
+#if ORTHANC_SANDBOXED == 0
   void PngReader::ReadFromFile(const std::string& filename)
   {
     FileRabi f(filename.c_str());
@@ -230,6 +238,7 @@ namespace Orthanc
 
     Read(rabi);
   }
+#endif
 
 
   namespace
diff --git a/Core/Images/PngReader.h b/Core/Images/PngReader.h
index b6ad811..fd18d26 100644
--- a/Core/Images/PngReader.h
+++ b/Core/Images/PngReader.h
@@ -41,6 +41,10 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/noncopyable.hpp>
 
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
 namespace Orthanc
 {
   class PngReader : 
@@ -59,7 +63,9 @@ namespace Orthanc
   public:
     PngReader();
 
+#if ORTHANC_SANDBOXED == 0
     void ReadFromFile(const std::string& filename);
+#endif
 
     void ReadFromMemory(const void* buffer,
                         size_t size);
diff --git a/Core/Images/PngWriter.cpp b/Core/Images/PngWriter.cpp
index 8a2d66a..5603bcf 100644
--- a/Core/Images/PngWriter.cpp
+++ b/Core/Images/PngWriter.cpp
@@ -40,6 +40,10 @@
 #include "../ChunkedBuffer.h"
 #include "../Toolbox.h"
 
+#if ORTHANC_SANDBOXED == 0
+#  include "../SystemToolbox.h"
+#endif
+
 
 // http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-4
 // http://zarb.org/~gc/html/libpng.html
@@ -202,6 +206,7 @@ namespace Orthanc
   }
 
 
+#if ORTHANC_SANDBOXED == 0
   void PngWriter::WriteToFileInternal(const std::string& filename,
                                       unsigned int width,
                                       unsigned int height,
@@ -211,7 +216,7 @@ namespace Orthanc
   {
     Prepare(width, height, pitch, format, buffer);
 
-    FILE* fp = Toolbox::OpenFile(filename, FileMode_WriteBinary);
+    FILE* fp = SystemToolbox::OpenFile(filename, FileMode_WriteBinary);
     if (!fp)
     {
       throw OrthancException(ErrorCode_CannotWriteFile);
@@ -229,7 +234,7 @@ namespace Orthanc
 
     fclose(fp);
   }
-
+#endif
 
 
   static void MemoryCallback(png_structp png_ptr, 
diff --git a/Core/Images/PngWriter.h b/Core/Images/PngWriter.h
index 591112f..7d8b87f 100644
--- a/Core/Images/PngWriter.h
+++ b/Core/Images/PngWriter.h
@@ -48,12 +48,14 @@ namespace Orthanc
                                      PixelFormat format,
                                      const void* buffer);
 
+#if ORTHANC_SANDBOXED == 0
     virtual void WriteToMemoryInternal(std::string& png,
                                        unsigned int width,
                                        unsigned int height,
                                        unsigned int pitch,
                                        PixelFormat format,
                                        const void* buffer);
+#endif
 
   private:
     struct PImpl;
diff --git a/Core/Logging.cpp b/Core/Logging.cpp
index 7bce92b..cffdb5b 100644
--- a/Core/Logging.cpp
+++ b/Core/Logging.cpp
@@ -83,6 +83,7 @@ namespace Orthanc
 #include "OrthancException.h"
 #include "Enumerations.h"
 #include "Toolbox.h"
+#include "SystemToolbox.h"
 
 #include <fstream>
 #include <boost/filesystem.hpp>
@@ -150,7 +151,7 @@ namespace Orthanc
 
       boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
       boost::filesystem::path root(directory);
-      boost::filesystem::path exe(Toolbox::GetPathToExecutable());
+      boost::filesystem::path exe(SystemToolbox::GetPathToExecutable());
       
       if (!boost::filesystem::exists(root) ||
           !boost::filesystem::is_directory(root))
@@ -166,7 +167,7 @@ namespace Orthanc
               now.time_of_day().hours(),
               now.time_of_day().minutes(),
               now.time_of_day().seconds(),
-              Toolbox::GetProcessId());
+              SystemToolbox::GetProcessId());
 
       std::string programName = exe.filename().replace_extension("").string();
 
@@ -318,113 +319,123 @@ namespace Orthanc
         return;
       }
 
-      LogLevel l = StringToLogLevel(level);
-      
-      if ((l == LogLevel_Info  && !loggingContext_->infoEnabled_) ||
-          (l == LogLevel_Trace && !loggingContext_->traceEnabled_))
+      try
       {
-        // This logging level is disabled, directly exit and unlock
-        // the mutex to speed-up things. The stream is set to "/dev/null"
+        LogLevel l = StringToLogLevel(level);
+      
+        if ((l == LogLevel_Info  && !loggingContext_->infoEnabled_) ||
+            (l == LogLevel_Trace && !loggingContext_->traceEnabled_))
+        {
+          // This logging level is disabled, directly exit and unlock
+          // the mutex to speed-up things. The stream is set to "/dev/null"
+          lock_.unlock();
+          return;
+        }
+
+        // Compute the header of the line, temporary release the lock as
+        // this is a time-consuming operation
         lock_.unlock();
-        return;
-      }
+        std::string header;
 
-      // Compute the header of the line, temporary release the lock as
-      // this is a time-consuming operation
-      lock_.unlock();
-      std::string header;
+        {
+          boost::filesystem::path path(file);
+          boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
+          boost::posix_time::time_duration duration = now.time_of_day();
+
+          /**
+             From Google Log documentation:
+
+             "Log lines have this form:
+
+             Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
+
+             where the fields are defined as follows:
+
+             L                A single character, representing the log level (eg 'I' for INFO)
+             mm               The month (zero padded; ie May is '05')
+             dd               The day (zero padded)
+             hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds
+             threadid         The space-padded thread ID as returned by GetTID() (this matches the PID on Linux)
+             file             The file name
+             line             The line number
+             msg              The user-supplied message"
+
+             In this implementation, "threadid" is not printed.
+          **/
+
+          char date[32];
+          sprintf(date, "%c%02d%02d %02d:%02d:%02d.%06d ",
+                  level[0],
+                  now.date().month().as_number(),
+                  now.date().day().as_number(),
+                  duration.hours(),
+                  duration.minutes(),
+                  duration.seconds(),
+                  static_cast<int>(duration.fractional_seconds()));
+
+          header = std::string(date) + path.filename().string() + ":" + boost::lexical_cast<std::string>(line) + "] ";
+        }
 
-      {
-        boost::filesystem::path path(file);
-        boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
-        boost::posix_time::time_duration duration = now.time_of_day();
-
-        /**
-           From Google Log documentation:
-
-           "Log lines have this form:
-
-           Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
-
-           where the fields are defined as follows:
-
-           L                A single character, representing the log level (eg 'I' for INFO)
-           mm               The month (zero padded; ie May is '05')
-           dd               The day (zero padded)
-           hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds
-           threadid         The space-padded thread ID as returned by GetTID() (this matches the PID on Linux)
-           file             The file name
-           line             The line number
-           msg              The user-supplied message"
-
-           In this implementation, "threadid" is not printed.
-         **/
-
-        char date[32];
-        sprintf(date, "%c%02d%02d %02d:%02d:%02d.%06d ",
-                level[0],
-                now.date().month().as_number(),
-                now.date().day().as_number(),
-                duration.hours(),
-                duration.minutes(),
-                duration.seconds(),
-                static_cast<int>(duration.fractional_seconds()));
-
-        header = std::string(date) + path.filename().string() + ":" + boost::lexical_cast<std::string>(line) + "] ";
-      }
 
+        // The header is computed, we now re-lock the mutex to access
+        // the stream objects. Pay attention that "loggingContext_",
+        // "infoEnabled_" or "traceEnabled_" might have changed while
+        // the mutex was unlocked.
+        lock_.lock();
 
-      // The header is computed, we now re-lock the mutex to access
-      // the stream objects. Pay attention that "loggingContext_",
-      // "infoEnabled_" or "traceEnabled_" might have changed while
-      // the mutex was unlocked.
-      lock_.lock();
+        if (loggingContext_.get() == NULL)
+        {
+          fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n");
+          return;
+        }
 
-      if (loggingContext_.get() == NULL)
-      {
-        fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n");
-        return;
-      }
+        switch (l)
+        {
+          case LogLevel_Error:
+            stream_ = loggingContext_->error_;
+            break;
 
-      switch (l)
-      {
-        case LogLevel_Error:
-          stream_ = loggingContext_->error_;
-          break;
+          case LogLevel_Warning:
+            stream_ = loggingContext_->warning_;
+            break;
 
-        case LogLevel_Warning:
-          stream_ = loggingContext_->warning_;
-          break;
+          case LogLevel_Info:
+            if (loggingContext_->infoEnabled_)
+            {
+              stream_ = loggingContext_->info_;
+            }
 
-        case LogLevel_Info:
-          if (loggingContext_->infoEnabled_)
-          {
-            stream_ = loggingContext_->info_;
-          }
+            break;
 
-          break;
+          case LogLevel_Trace:
+            if (loggingContext_->traceEnabled_)
+            {
+              stream_ = loggingContext_->info_;
+            }
 
-        case LogLevel_Trace:
-          if (loggingContext_->traceEnabled_)
-          {
-            stream_ = loggingContext_->info_;
-          }
+            break;
 
-          break;
+          default:
+            throw OrthancException(ErrorCode_InternalError);
+        }
 
-        default:
-          throw OrthancException(ErrorCode_InternalError);
-      }
+        if (stream_ == &null_)
+        {
+          // The logging is disabled for this level. The stream is the
+          // "null_" member of this object, so we can release the global
+          // mutex.
+          lock_.unlock();
+        }
 
-      if (stream_ == &null_)
-      {
-        // The logging is disabled for this level. The stream is the
-        // "null_" member of this object, so we can release the global
-        // mutex.
-        lock_.unlock();
+        (*stream_) << header;
+      }
+      catch (...)
+      { 
+        // Something is going really wrong, probably running out of
+        // memory. Fallback to a degraded mode.
+        stream_ = loggingContext_->error_;
+        (*stream_) << "E???? ??:??:??.?????? ] ";
       }
-
-      (*stream_) << header;
     }
 
 
diff --git a/Core/Logging.h b/Core/Logging.h
index 7318246..abec83f 100644
--- a/Core/Logging.h
+++ b/Core/Logging.h
@@ -34,6 +34,10 @@
 
 #include <iostream>
 
+#if !defined(ORTHANC_ENABLE_LOGGING)
+#  error The macro ORTHANC_ENABLE_LOGGING must be defined
+#endif
+
 namespace Orthanc
 {
   namespace Logging
@@ -66,6 +70,12 @@ namespace Orthanc
       {
         return *this;
       }
+
+      // This overload fixes build problems with Visual Studio 2015
+      std::ostream& operator<< (const char* message)
+      {
+        return *this;
+      }
     };
   }
 }
@@ -104,6 +114,12 @@ namespace Orthanc
       {
         return (*stream_) << message;
       }
+
+      // This overload fixes build problems with Visual Studio 2015
+      std::ostream& operator<< (const char* message)
+      {
+        return (*stream_) << message;
+      }
     };
   }
 }
diff --git a/Core/Lua/LuaContext.cpp b/Core/Lua/LuaContext.cpp
index cc6b710..e6a7d63 100644
--- a/Core/Lua/LuaContext.cpp
+++ b/Core/Lua/LuaContext.cpp
@@ -497,6 +497,10 @@ namespace Orthanc
       // Lua can convert most types to strings by default.
       result = std::string(lua_tostring(lua_, top));
     }
+    else if (lua_isboolean(lua_, top))
+    {
+      result = lua_toboolean(lua_, top) ? true : false;
+    }
     else
     {
       LOG(WARNING) << "Unsupported Lua type when returning Json";
diff --git a/Core/Lua/LuaFunctionCall.cpp b/Core/Lua/LuaFunctionCall.cpp
index 1e9c941..a52afe6 100644
--- a/Core/Lua/LuaFunctionCall.cpp
+++ b/Core/Lua/LuaFunctionCall.cpp
@@ -166,4 +166,26 @@ namespace Orthanc
 
     PushJson(json);
   }
+
+
+  void LuaFunctionCall::PushDicom(const DicomMap& dicom)
+  {
+    DicomArray a(dicom);
+    PushDicom(a);
+  }
+
+
+  void LuaFunctionCall::PushDicom(const DicomArray& dicom)
+  {
+    Json::Value value = Json::objectValue;
+
+    for (size_t i = 0; i < dicom.GetSize(); i++)
+    {
+      const DicomValue& v = dicom.GetElement(i).GetValue();
+      std::string s = (v.IsNull() || v.IsBinary()) ? "" : v.GetContent();
+      value[dicom.GetElement(i).GetTag().Format()] = s;
+    }
+
+    PushJson(value);
+  }
 }
diff --git a/Core/Lua/LuaFunctionCall.h b/Core/Lua/LuaFunctionCall.h
index 3dff4f1..a4cdc38 100644
--- a/Core/Lua/LuaFunctionCall.h
+++ b/Core/Lua/LuaFunctionCall.h
@@ -34,6 +34,9 @@
 
 #include "LuaContext.h"
 
+#include "../DicomFormat/DicomArray.h"
+#include "../DicomFormat/DicomMap.h"
+
 #include <json/json.h>
 
 namespace Orthanc
@@ -64,6 +67,10 @@ namespace Orthanc
 
     void PushStringMap(const std::map<std::string, std::string>& value);
 
+    void PushDicom(const DicomMap& dicom);
+
+    void PushDicom(const DicomArray& dicom);
+
     void Execute()
     {
       ExecuteInternal(0);
diff --git a/Core/MultiThreading/BagOfTasksProcessor.cpp b/Core/MultiThreading/BagOfTasksProcessor.cpp
index dc2034f..c409f1c 100644
--- a/Core/MultiThreading/BagOfTasksProcessor.cpp
+++ b/Core/MultiThreading/BagOfTasksProcessor.cpp
@@ -33,8 +33,10 @@
 #include "../PrecompiledHeaders.h"
 #include "BagOfTasksProcessor.h"
 
+#include "../Logging.h"
 #include "../OrthancException.h"
 
+#include <stdio.h>
 
 namespace Orthanc
 {
@@ -58,12 +60,19 @@ namespace Orthanc
       {
         return command_->Execute();
       }
-      catch (OrthancException&)
+      catch (OrthancException& e)
       {
+        LOG(ERROR) << "Exception while processing a bag of tasks: " << e.What();
         return false;
       }
-      catch (std::runtime_error&)
+      catch (std::runtime_error& e)
       {
+        LOG(ERROR) << "Runtime exception while processing a bag of tasks: " << e.what();
+        return false;
+      }
+      catch (...)
+      {
+        LOG(ERROR) << "Native exception while processing a bag of tasks";
         return false;
       }
     }
@@ -75,6 +84,20 @@ namespace Orthanc
   };
 
 
+  void BagOfTasksProcessor::SignalProgress(Task& task,
+                                           Bag& bag)
+  {
+    assert(bag.done_ < bag.size_);
+
+    bag.done_ += 1;
+
+    if (bag.done_ == bag.size_)
+    {
+      exitStatus_[task.GetBag()] = (bag.status_ == BagStatus_Running);
+      bagFinished_.notify_all();
+    }
+  }
+
   void BagOfTasksProcessor::Worker(BagOfTasksProcessor* that)
   {
     while (that->continue_)
@@ -93,8 +116,9 @@ namespace Orthanc
 
           if (bag->second.status_ != BagStatus_Running)
           {
-            // This bag of task has failed or is tagged as canceled, do nothing
-            bag->second.done_ += 1;
+            // Do not execute this task, as its parent bag of tasks
+            // has failed or is tagged as canceled
+            that->SignalProgress(task, bag->second);
             continue;
           }
         }
@@ -112,14 +136,7 @@ namespace Orthanc
             bag->second.status_ = BagStatus_Failed;
           }
 
-          assert(bag->second.done_ < bag->second.size_);
-          bag->second.done_ += 1;
-
-          if (bag->second.done_ == bag->second.size_)
-          {
-            that->exitStatus_[task.GetBag()] = (bag->second.status_ == BagStatus_Running);
-            that->bagFinished_.notify_all();
-          }
+          that->SignalProgress(task, bag->second);
         }
       }
     }
diff --git a/Core/MultiThreading/BagOfTasksProcessor.h b/Core/MultiThreading/BagOfTasksProcessor.h
index 51c0ff1..a0dff6e 100644
--- a/Core/MultiThreading/BagOfTasksProcessor.h
+++ b/Core/MultiThreading/BagOfTasksProcessor.h
@@ -64,10 +64,10 @@ namespace Orthanc
       {
       }
 
-      Bag(size_t size) : 
-      size_(size),
-      done_(0),
-      status_(BagStatus_Running)
+      explicit Bag(size_t size) : 
+        size_(size),
+        done_(0),
+        status_(BagStatus_Running)
       {
       }
     };
@@ -97,6 +97,9 @@ namespace Orthanc
 
     float GetProgress(int64_t bag);
 
+    void SignalProgress(Task& task,
+                        Bag& bag);
+
   public:
     class Handle : public boost::noncopyable
     {
@@ -137,7 +140,7 @@ namespace Orthanc
     };
   
 
-    BagOfTasksProcessor(size_t countThreads);
+    explicit BagOfTasksProcessor(size_t countThreads);
 
     ~BagOfTasksProcessor();
 
diff --git a/Core/MultiThreading/ReaderWriterLock.cpp b/Core/MultiThreading/ReaderWriterLock.cpp
index a2c6acb..25bc231 100644
--- a/Core/MultiThreading/ReaderWriterLock.cpp
+++ b/Core/MultiThreading/ReaderWriterLock.cpp
@@ -59,7 +59,7 @@ namespace Orthanc
       }
 
     public:
-      ReaderLockable(boost::shared_mutex& lock) : lock_(lock)
+      explicit ReaderLockable(boost::shared_mutex& lock) : lock_(lock)
       {
       }
     };
@@ -82,10 +82,9 @@ namespace Orthanc
       }
 
     public:
-      WriterLockable(boost::shared_mutex& lock) : lock_(lock)
+      explicit WriterLockable(boost::shared_mutex& lock) : lock_(lock)
       {
       }
-
     };
   }
 
diff --git a/Core/MultiThreading/RunnableWorkersPool.cpp b/Core/MultiThreading/RunnableWorkersPool.cpp
index 30c67e6..f688e91 100644
--- a/Core/MultiThreading/RunnableWorkersPool.cpp
+++ b/Core/MultiThreading/RunnableWorkersPool.cpp
@@ -52,25 +52,33 @@ namespace Orthanc
       {
         while (that->continue_)
         {
-          std::auto_ptr<IDynamicObject>  obj(that->queue_.Dequeue(100));
-          if (obj.get() != NULL)
+          try
           {
-            try
+            std::auto_ptr<IDynamicObject>  obj(that->queue_.Dequeue(100));
+            if (obj.get() != NULL)
             {
               IRunnableBySteps& runnable = *dynamic_cast<IRunnableBySteps*>(obj.get());
-            
+              
               bool wishToContinue = runnable.Step();
-
+              
               if (wishToContinue)
               {
                 // The runnable wishes to continue, reinsert it at the beginning of the queue
                 that->queue_.Enqueue(obj.release());
               }
             }
-            catch (OrthancException& e)
-            {
-              LOG(ERROR) << "Exception in a pool of working threads: " << e.What();
-            }
+          }
+          catch (OrthancException& e)
+          {
+            LOG(ERROR) << "Exception while handling some runnable object: " << e.What();
+          }
+          catch (std::bad_alloc&)
+          {
+            LOG(ERROR) << "Not enough memory to handle some runnable object";
+          }
+          catch (...)
+          {
+            LOG(ERROR) << "Native exception while handling some runnable object";
           }
         }
       }
diff --git a/Core/MultiThreading/RunnableWorkersPool.h b/Core/MultiThreading/RunnableWorkersPool.h
index bde1edc..9bd2a2b 100644
--- a/Core/MultiThreading/RunnableWorkersPool.h
+++ b/Core/MultiThreading/RunnableWorkersPool.h
@@ -47,7 +47,7 @@ namespace Orthanc
     void Stop();
 
   public:
-    RunnableWorkersPool(size_t countWorkers);
+    explicit RunnableWorkersPool(size_t countWorkers);
 
     ~RunnableWorkersPool();
 
diff --git a/Core/MultiThreading/Semaphore.cpp b/Core/MultiThreading/Semaphore.cpp
index 4de6cb8..82d5aa5 100644
--- a/Core/MultiThreading/Semaphore.cpp
+++ b/Core/MultiThreading/Semaphore.cpp
@@ -40,10 +40,6 @@ namespace Orthanc
 {
   Semaphore::Semaphore(unsigned int count) : count_(count)
   {
-    if (count == 0)
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
   }
 
   void Semaphore::Release()
diff --git a/Core/MultiThreading/Semaphore.h b/Core/MultiThreading/Semaphore.h
index 7bd6376..31e1392 100644
--- a/Core/MultiThreading/Semaphore.h
+++ b/Core/MultiThreading/Semaphore.h
@@ -50,5 +50,23 @@ namespace Orthanc
     void Release();
 
     void Acquire();
+
+    class Locker : public boost::noncopyable
+    {
+    private:
+      Semaphore&  that_;
+
+    public:
+      explicit Locker(Semaphore& that) :
+        that_(that)
+      {
+        that_.Acquire();
+      }
+
+      ~Locker()
+      {
+        that_.Release();
+      }
+    };
   };
 }
diff --git a/Core/MultiThreading/SharedMessageQueue.cpp b/Core/MultiThreading/SharedMessageQueue.cpp
index 34508ae..0c1a727 100644
--- a/Core/MultiThreading/SharedMessageQueue.cpp
+++ b/Core/MultiThreading/SharedMessageQueue.cpp
@@ -185,4 +185,24 @@ namespace Orthanc
     boost::mutex::scoped_lock lock(mutex_);
     isFifo_ = false;
   }
+
+  void SharedMessageQueue::Clear()
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    if (queue_.empty())
+    {
+      return;
+    }
+    else
+    {
+      while (!queue_.empty())
+      {
+        std::auto_ptr<IDynamicObject> message(queue_.front());
+        queue_.pop_front();
+      }
+
+      emptied_.notify_all();
+    }
+  }
 }
diff --git a/Core/MultiThreading/SharedMessageQueue.h b/Core/MultiThreading/SharedMessageQueue.h
index 71728c0..211b774 100644
--- a/Core/MultiThreading/SharedMessageQueue.h
+++ b/Core/MultiThreading/SharedMessageQueue.h
@@ -78,5 +78,7 @@ namespace Orthanc
     void SetFifoPolicy();
 
     void SetLifoPolicy();
+
+    void Clear();
   };
 }
diff --git a/Core/OrthancException.h b/Core/OrthancException.h
index 5afa41f..d5544dd 100644
--- a/Core/OrthancException.h
+++ b/Core/OrthancException.h
@@ -45,7 +45,7 @@ namespace Orthanc
     HttpStatus httpStatus_;
 
   public:
-    OrthancException(ErrorCode errorCode) : 
+    explicit OrthancException(ErrorCode errorCode) : 
       errorCode_(errorCode),
       httpStatus_(ConvertErrorCodeToHttpStatus(errorCode))
     {
diff --git a/Core/Pkcs11.cpp b/Core/Pkcs11.cpp
index d0ed318..613a464 100644
--- a/Core/Pkcs11.cpp
+++ b/Core/Pkcs11.cpp
@@ -33,10 +33,6 @@
 #include "PrecompiledHeaders.h"
 #include "Pkcs11.h"
 
-#if ORTHANC_PKCS11_ENABLED != 1 || ORTHANC_SSL_ENABLED != 1
-#  error This file cannot be used if OpenSSL or PKCS#11 support is disabled
-#endif
-
 
 #if defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_ECDSA) || defined(OPENSSL_NO_ECDH)
 #  error OpenSSL was compiled without support for RSA, EC, ECDSA or ECDH
@@ -45,12 +41,12 @@
 
 #include "Logging.h"
 #include "OrthancException.h"
-#include "Toolbox.h"
+#include "SystemToolbox.h"
 
 extern "C"
 {
-#include <libp11/engine.h>  // This is P11's "engine.h"
-#include <libp11/libp11.h>
+#  include <libp11/engine.h>  // This is P11's "engine.h"
+#  include <libp11/libp11.h>
 }
 
 #include <openssl/engine.h>
@@ -261,7 +257,7 @@ namespace Orthanc
       }
 
       if (module.empty() ||
-          !Toolbox::IsRegularFile(module))
+          !SystemToolbox::IsRegularFile(module))
       {
         LOG(ERROR) << "The PKCS#11 module must be a path to one shared library (DLL or .so)";
         throw OrthancException(ErrorCode_InexistentFile);
diff --git a/Core/Pkcs11.h b/Core/Pkcs11.h
index 3a56c74..f2e1cba 100644
--- a/Core/Pkcs11.h
+++ b/Core/Pkcs11.h
@@ -32,7 +32,23 @@
 
 #pragma once
 
-#if ORTHANC_PKCS11_ENABLED != 1 || ORTHANC_SSL_ENABLED != 1
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_PKCS11)
+#  error The macro ORTHANC_ENABLE_PKCS11 must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_SSL)
+#  error The macro ORTHANC_ENABLE_SSL must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+#  error This file cannot be used in sandboxed environments
+#endif
+
+#if ORTHANC_ENABLE_PKCS11 != 1 || ORTHANC_ENABLE_SSL != 1
 #  error This file cannot be used if OpenSSL or PKCS#11 support is disabled
 #endif
 
diff --git a/Core/PrecompiledHeaders.h b/Core/PrecompiledHeaders.h
index e22f012..1422e30 100644
--- a/Core/PrecompiledHeaders.h
+++ b/Core/PrecompiledHeaders.h
@@ -48,7 +48,7 @@
 
 #include <json/value.h>
 
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
 #include <pugixml.hpp>
 #endif
 
@@ -56,6 +56,5 @@
 #include "Logging.h"
 #include "OrthancException.h"
 #include "Toolbox.h"
-#include "Uuid.h"
 
 #endif
diff --git a/Core/RestApi/RestApi.cpp b/Core/RestApi/RestApi.cpp
index c314582..f9e6fa7 100644
--- a/Core/RestApi/RestApi.cpp
+++ b/Core/RestApi/RestApi.cpp
@@ -185,7 +185,7 @@ namespace Orthanc
   {
     RestApiOutput wrappedOutput(output, method);
 
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
     {
       // Look if the client wishes XML answers instead of JSON
       // http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#z3
diff --git a/Core/RestApi/RestApiOutput.cpp b/Core/RestApi/RestApiOutput.cpp
index 0d137b9..c9901c4 100644
--- a/Core/RestApi/RestApiOutput.cpp
+++ b/Core/RestApi/RestApiOutput.cpp
@@ -35,6 +35,7 @@
 
 #include "../Logging.h"
 #include "../OrthancException.h"
+#include "../Toolbox.h"
 
 #include <boost/lexical_cast.hpp>
 
@@ -91,10 +92,10 @@ namespace Orthanc
 
     if (convertJsonToXml_)
     {
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
       std::string s;
       Toolbox::JsonToXml(s, value);
-      output_.SetContentType("application/xml");
+      output_.SetContentType("application/xml; charset=utf-8");
       output_.Answer(s);
 #else
       LOG(ERROR) << "Orthanc was compiled without XML support";
@@ -104,7 +105,7 @@ namespace Orthanc
     else
     {
       Json::StyledWriter writer;
-      output_.SetContentType("application/json");
+      output_.SetContentType("application/json; charset=utf-8");
       output_.Answer(writer.write(value));
     }
 
diff --git a/Core/SystemToolbox.cpp b/Core/SystemToolbox.cpp
new file mode 100644
index 0000000..e22a006
--- /dev/null
+++ b/Core/SystemToolbox.cpp
@@ -0,0 +1,539 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "PrecompiledHeaders.h"
+#include "SystemToolbox.h"
+
+
+#if BOOST_HAS_DATE_TIME == 1
+#  include <boost/date_time/posix_time/posix_time.hpp>
+#endif
+
+
+#if defined(_WIN32)
+#  include <windows.h>
+#  include <process.h>   // For "_spawnvp()" and "_getpid()"
+#else
+#  include <unistd.h>    // For "execvp()"
+#  include <sys/wait.h>  // For "waitpid()"
+#endif
+
+
+#if defined(__APPLE__) && defined(__MACH__)
+#  include <mach-o/dyld.h> /* _NSGetExecutablePath */
+#  include <limits.h>      /* PATH_MAX */
+#endif
+
+
+#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+#  include <limits.h>      /* PATH_MAX */
+#  include <signal.h>
+#  include <unistd.h>
+#endif
+
+
+// Inclusions for UUID
+// http://stackoverflow.com/a/1626302
+
+extern "C"
+{
+#ifdef WIN32
+#  include <rpc.h>
+#else
+#  include <uuid/uuid.h>
+#endif
+}
+
+
+#include "Logging.h"
+#include "OrthancException.h"
+#include "Toolbox.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+
+namespace Orthanc
+{
+  static bool finish_;
+  static ServerBarrierEvent barrierEvent_;
+
+#if defined(_WIN32)
+  static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType)
+  {
+    // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx
+    finish_ = true;
+    return true;
+  }
+#else
+  static void SignalHandler(int signal)
+  {
+    if (signal == SIGHUP)
+    {
+      barrierEvent_ = ServerBarrierEvent_Reload;
+    }
+
+    finish_ = true;
+  }
+#endif
+
+
+  static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag)
+  {
+#if defined(_WIN32)
+    SetConsoleCtrlHandler(ConsoleControlHandler, true);
+#else
+    signal(SIGINT, SignalHandler);
+    signal(SIGQUIT, SignalHandler);
+    signal(SIGTERM, SignalHandler);
+    signal(SIGHUP, SignalHandler);
+#endif
+  
+    // Active loop that awakens every 100ms
+    finish_ = false;
+    barrierEvent_ = ServerBarrierEvent_Stop;
+    while (!(*stopFlag || finish_))
+    {
+      Toolbox::USleep(100 * 1000);
+    }
+
+#if defined(_WIN32)
+    SetConsoleCtrlHandler(ConsoleControlHandler, false);
+#else
+    signal(SIGINT, NULL);
+    signal(SIGQUIT, NULL);
+    signal(SIGTERM, NULL);
+    signal(SIGHUP, NULL);
+#endif
+
+    return barrierEvent_;
+  }
+
+
+  ServerBarrierEvent SystemToolbox::ServerBarrier(const bool& stopFlag)
+  {
+    return ServerBarrierInternal(&stopFlag);
+  }
+
+
+  ServerBarrierEvent SystemToolbox::ServerBarrier()
+  {
+    const bool stopFlag = false;
+    return ServerBarrierInternal(&stopFlag);
+  }
+
+
+  static std::streamsize GetStreamSize(std::istream& f)
+  {
+    // http://www.cplusplus.com/reference/iostream/istream/tellg/
+    f.seekg(0, std::ios::end);
+    std::streamsize size = f.tellg();
+    f.seekg(0, std::ios::beg);
+
+    return size;
+  }
+
+
+  void SystemToolbox::ReadFile(std::string& content,
+                               const std::string& path) 
+  {
+    if (!IsRegularFile(path))
+    {
+      LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
+      throw OrthancException(ErrorCode_RegularFileExpected);
+    }
+
+    boost::filesystem::ifstream f;
+    f.open(path, std::ifstream::in | std::ifstream::binary);
+    if (!f.good())
+    {
+      throw OrthancException(ErrorCode_InexistentFile);
+    }
+
+    std::streamsize size = GetStreamSize(f);
+    content.resize(size);
+    if (size != 0)
+    {
+      f.read(reinterpret_cast<char*>(&content[0]), size);
+    }
+
+    f.close();
+  }
+
+
+  bool SystemToolbox::ReadHeader(std::string& header,
+                                 const std::string& path,
+                                 size_t headerSize)
+  {
+    if (!IsRegularFile(path))
+    {
+      LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
+      throw OrthancException(ErrorCode_RegularFileExpected);
+    }
+
+    boost::filesystem::ifstream f;
+    f.open(path, std::ifstream::in | std::ifstream::binary);
+    if (!f.good())
+    {
+      throw OrthancException(ErrorCode_InexistentFile);
+    }
+
+    bool full = true;
+
+    {
+      std::streamsize size = GetStreamSize(f);
+      if (size <= 0)
+      {
+        headerSize = 0;
+        full = false;
+      }
+      else if (static_cast<size_t>(size) < headerSize)
+      {
+        headerSize = size;  // Truncate to the size of the file
+        full = false;
+      }
+    }
+
+    header.resize(headerSize);
+    if (headerSize != 0)
+    {
+      f.read(reinterpret_cast<char*>(&header[0]), headerSize);
+    }
+
+    f.close();
+
+    return full;
+  }
+
+
+  void SystemToolbox::WriteFile(const void* content,
+                                size_t size,
+                                const std::string& path)
+  {
+    boost::filesystem::ofstream f;
+    f.open(path, std::ofstream::out | std::ofstream::binary);
+    if (!f.good())
+    {
+      throw OrthancException(ErrorCode_CannotWriteFile);
+    }
+
+    if (size != 0)
+    {
+      f.write(reinterpret_cast<const char*>(content), size);
+
+      if (!f.good())
+      {
+        f.close();
+        throw OrthancException(ErrorCode_FileStorageCannotWrite);
+      }
+    }
+
+    f.close();
+  }
+
+
+  void SystemToolbox::WriteFile(const std::string& content,
+                                const std::string& path)
+  {
+    WriteFile(content.size() > 0 ? content.c_str() : NULL,
+              content.size(), path);
+  }
+
+
+  void SystemToolbox::RemoveFile(const std::string& path)
+  {
+    if (boost::filesystem::exists(path))
+    {
+      if (IsRegularFile(path))
+      {
+        boost::filesystem::remove(path);
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_RegularFileExpected);
+      }
+    }
+  }
+
+
+  uint64_t SystemToolbox::GetFileSize(const std::string& path)
+  {
+    try
+    {
+      return static_cast<uint64_t>(boost::filesystem::file_size(path));
+    }
+    catch (boost::filesystem::filesystem_error&)
+    {
+      throw OrthancException(ErrorCode_InexistentFile);
+    }
+  }
+
+
+  void SystemToolbox::MakeDirectory(const std::string& path)
+  {
+    if (boost::filesystem::exists(path))
+    {
+      if (!boost::filesystem::is_directory(path))
+      {
+        throw OrthancException(ErrorCode_DirectoryOverFile);
+      }
+    }
+    else
+    {
+      if (!boost::filesystem::create_directories(path))
+      {
+        throw OrthancException(ErrorCode_MakeDirectory);
+      }
+    }
+  }
+
+
+  bool SystemToolbox::IsExistingFile(const std::string& path)
+  {
+    return boost::filesystem::exists(path);
+  }
+
+
+#if defined(_WIN32)
+  static std::string GetPathToExecutableInternal()
+  {
+    // Yes, this is ugly, but there is no simple way to get the 
+    // required buffer size, so we use a big constant
+    std::vector<char> buffer(32768);
+    /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1));
+    return std::string(&buffer[0]);
+  }
+
+#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+  static std::string GetPathToExecutableInternal()
+  {
+    std::vector<char> buffer(PATH_MAX + 1);
+    ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
+    if (bytes == 0)
+    {
+      throw OrthancException(ErrorCode_PathToExecutable);
+    }
+
+    return std::string(&buffer[0]);
+  }
+
+#elif defined(__APPLE__) && defined(__MACH__)
+  static std::string GetPathToExecutableInternal()
+  {
+    char pathbuf[PATH_MAX + 1];
+    unsigned int  bufsize = static_cast<int>(sizeof(pathbuf));
+
+    _NSGetExecutablePath( pathbuf, &bufsize);
+
+    return std::string(pathbuf);
+  }
+
+#else
+#error Support your platform here
+#endif
+
+
+  std::string SystemToolbox::GetPathToExecutable()
+  {
+    boost::filesystem::path p(GetPathToExecutableInternal());
+    return boost::filesystem::absolute(p).string();
+  }
+
+
+  std::string SystemToolbox::GetDirectoryOfExecutable()
+  {
+    boost::filesystem::path p(GetPathToExecutableInternal());
+    return boost::filesystem::absolute(p.parent_path()).string();
+  }
+
+
+  void SystemToolbox::ExecuteSystemCommand(const std::string& command,
+                                           const std::vector<std::string>& arguments)
+  {
+    // Convert the arguments as a C array
+    std::vector<char*>  args(arguments.size() + 2);
+
+    args.front() = const_cast<char*>(command.c_str());
+
+    for (size_t i = 0; i < arguments.size(); i++)
+    {
+      args[i + 1] = const_cast<char*>(arguments[i].c_str());
+    }
+
+    args.back() = NULL;
+
+    int status;
+
+#if defined(_WIN32)
+    // http://msdn.microsoft.com/en-us/library/275khfab.aspx
+    status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0]));
+
+#else
+    int pid = fork();
+
+    if (pid == -1)
+    {
+      // Error in fork()
+#if ORTHANC_ENABLE_LOGGING == 1
+      LOG(ERROR) << "Cannot fork a child process";
+#endif
+
+      throw OrthancException(ErrorCode_SystemCommand);
+    }
+    else if (pid == 0)
+    {
+      // Execute the system command in the child process
+      execvp(command.c_str(), &args[0]);
+
+      // We should never get here
+      _exit(1);
+    }
+    else
+    {
+      // Wait for the system command to exit
+      waitpid(pid, &status, 0);
+    }
+#endif
+
+    if (status != 0)
+    {
+#if ORTHANC_ENABLE_LOGGING == 1
+      LOG(ERROR) << "System command failed with status code " << status;
+#endif
+
+      throw OrthancException(ErrorCode_SystemCommand);
+    }
+  }
+
+
+  int SystemToolbox::GetProcessId()
+  {
+#if defined(_WIN32)
+    return static_cast<int>(_getpid());
+#else
+    return static_cast<int>(getpid());
+#endif
+  }
+
+
+  bool SystemToolbox::IsRegularFile(const std::string& path)
+  {
+    namespace fs = boost::filesystem;
+
+    try
+    {
+      if (fs::exists(path))
+      {
+        fs::file_status status = fs::status(path);
+        return (status.type() == boost::filesystem::regular_file ||
+                status.type() == boost::filesystem::reparse_file);   // Fix BitBucket issue #11
+      }
+    }
+    catch (fs::filesystem_error&)
+    {
+    }
+
+    return false;
+  }
+
+
+  FILE* SystemToolbox::OpenFile(const std::string& path,
+                                FileMode mode)
+  {
+#if defined(_WIN32)
+    // TODO Deal with special characters by converting to the current locale
+#endif
+
+    const char* m;
+    switch (mode)
+    {
+      case FileMode_ReadBinary:
+        m = "rb";
+        break;
+
+      case FileMode_WriteBinary:
+        m = "wb";
+        break;
+
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
+    return fopen(path.c_str(), m);
+  }
+
+
+  std::string SystemToolbox::GenerateUuid()
+  {
+#ifdef WIN32
+    UUID uuid;
+    UuidCreate ( &uuid );
+
+    unsigned char * str;
+    UuidToStringA ( &uuid, &str );
+
+    std::string s( ( char* ) str );
+
+    RpcStringFreeA ( &str );
+#else
+    uuid_t uuid;
+    uuid_generate_random ( uuid );
+    char s[37];
+    uuid_unparse ( uuid, s );
+#endif
+    return s;
+  }
+
+
+#if BOOST_HAS_DATE_TIME == 1
+  std::string SystemToolbox::GetNowIsoString()
+  {
+    boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
+    return boost::posix_time::to_iso_string(now);
+  }
+
+  void SystemToolbox::GetNowDicom(std::string& date,
+                                  std::string& time)
+  {
+    boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
+    tm tm = boost::posix_time::to_tm(now);
+
+    char s[32];
+    sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+    date.assign(s);
+
+    // TODO milliseconds
+    sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
+    time.assign(s);
+  }
+#endif
+}
diff --git a/Core/OrthancException.h b/Core/SystemToolbox.h
similarity index 52%
copy from Core/OrthancException.h
copy to Core/SystemToolbox.h
index 5afa41f..e62b529 100644
--- a/Core/OrthancException.h
+++ b/Core/SystemToolbox.h
@@ -32,45 +32,71 @@
 
 #pragma once
 
-#include <stdint.h>
-#include <string>
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+#  error The namespace SystemToolbox cannot be used in sandboxed environments
+#endif
+
 #include "Enumerations.h"
 
+#include <vector>
+#include <string>
+#include <stdint.h>
+
 namespace Orthanc
 {
-  class OrthancException
+  namespace SystemToolbox
   {
-  protected:
-    ErrorCode  errorCode_;
-    HttpStatus httpStatus_;
-
-  public:
-    OrthancException(ErrorCode errorCode) : 
-      errorCode_(errorCode),
-      httpStatus_(ConvertErrorCodeToHttpStatus(errorCode))
-    {
-    }
-
-    OrthancException(ErrorCode errorCode,
-                     HttpStatus httpStatus) :
-      errorCode_(errorCode),
-      httpStatus_(httpStatus)
-    {
-    }
-
-    ErrorCode GetErrorCode() const
-    {
-      return errorCode_;
-    }
-
-    HttpStatus GetHttpStatus() const
-    {
-      return httpStatus_;
-    }
-
-    const char* What() const
-    {
-      return EnumerationToString(errorCode_);
-    }
-  };
+    ServerBarrierEvent ServerBarrier(const bool& stopFlag);
+
+    ServerBarrierEvent ServerBarrier();
+
+    void ReadFile(std::string& content,
+                  const std::string& path);
+
+    bool ReadHeader(std::string& header,
+                    const std::string& path,
+                    size_t headerSize);
+
+    void WriteFile(const void* content,
+                   size_t size,
+                   const std::string& path);
+
+    void WriteFile(const std::string& content,
+                   const std::string& path);
+
+    void RemoveFile(const std::string& path);
+
+    uint64_t GetFileSize(const std::string& path);
+
+    void MakeDirectory(const std::string& path);
+
+    bool IsExistingFile(const std::string& path);
+
+    std::string GetPathToExecutable();
+
+    std::string GetDirectoryOfExecutable();
+
+    void ExecuteSystemCommand(const std::string& command,
+                              const std::vector<std::string>& arguments);
+
+    int GetProcessId();
+
+    bool IsRegularFile(const std::string& path);
+
+    FILE* OpenFile(const std::string& path,
+                   FileMode mode);
+
+    std::string GenerateUuid();
+
+#if BOOST_HAS_DATE_TIME == 1
+    std::string GetNowIsoString();
+
+    void GetNowDicom(std::string& date,
+                     std::string& time);
+#endif
+  }
 }
diff --git a/Core/Uuid.h b/Core/TemporaryFile.cpp
similarity index 58%
rename from Core/Uuid.h
rename to Core/TemporaryFile.cpp
index 88819a3..955489b 100644
--- a/Core/Uuid.h
+++ b/Core/TemporaryFile.cpp
@@ -30,57 +30,65 @@
  **/
 
 
-#pragma once
-
-#include <string>
-
-/**
- * GUID vs. UUID
- * The simple answer is: no difference, they are the same thing. Treat
- * them as a 16 byte (128 bits) value that is used as a unique
- * value. In Microsoft-speak they are called GUIDs, but call them
- * UUIDs when not using Microsoft-speak.
- * http://stackoverflow.com/questions/246930/is-there-any-difference-between-a-guid-and-a-uuid
- **/
+#include "PrecompiledHeaders.h"
+#include "TemporaryFile.h"
 
+#include "SystemToolbox.h"
 #include "Toolbox.h"
 
+#include <boost/filesystem.hpp>
+
 namespace Orthanc
 {
-  namespace Toolbox
+  static std::string CreateTemporaryPath(const char* extension)
   {
-    std::string GenerateUuid();
-
-    bool IsUuid(const std::string& str);
+#if BOOST_HAS_FILESYSTEM_V3 == 1
+    boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path();
+#elif defined(__linux__)
+    boost::filesystem::path tmpDir("/tmp");
+#else
+#error Support your platform here
+#endif
 
-    bool StartsWithUuid(const std::string& str);
+    // We use UUID to create unique path to temporary files
+    std::string filename = "Orthanc-" + Orthanc::SystemToolbox::GenerateUuid();
 
-    class TemporaryFile
+    if (extension != NULL)
     {
-    private:
-      std::string path_;
+      filename.append(extension);
+    }
 
-    public:
-      TemporaryFile();
+    tmpDir /= filename;
+    return tmpDir.string();
+  }
 
-      TemporaryFile(const char* extension);
 
-      ~TemporaryFile();
+  TemporaryFile::TemporaryFile() : 
+    path_(CreateTemporaryPath(NULL))
+  {
+  }
 
-      const std::string& GetPath() const
-      {
-        return path_;
-      }
 
-      void Write(const std::string& content)
-      {
-        Toolbox::WriteFile(content, path_);
-      }
+  TemporaryFile::TemporaryFile(const char* extension) :
+    path_(CreateTemporaryPath(extension))
+  {
+  }
 
-      void Read(std::string& content) const
-      {
-        Toolbox::ReadFile(content, path_);
-      }
-    };
+
+  TemporaryFile::~TemporaryFile()
+  {
+    boost::filesystem::remove(path_);
+  }
+
+
+  void TemporaryFile::Write(const std::string& content)
+  {
+    SystemToolbox::WriteFile(content, path_);
+  }
+
+
+  void TemporaryFile::Read(std::string& content) const
+  {
+    SystemToolbox::ReadFile(content, path_);
   }
 }
diff --git a/Core/Images/JpegReader.h b/Core/TemporaryFile.h
similarity index 77%
copy from Core/Images/JpegReader.h
copy to Core/TemporaryFile.h
index 5cb5551..1dd4f73 100644
--- a/Core/Images/JpegReader.h
+++ b/Core/TemporaryFile.h
@@ -32,26 +32,37 @@
 
 #pragma once
 
-#include "ImageAccessor.h"
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+#  error The class TemporaryFile cannot be used in sandboxed environments
+#endif
 
 #include <string>
-#include <boost/noncopyable.hpp>
 
 namespace Orthanc
 {
-  class JpegReader : 
-    public ImageAccessor,
-    public boost::noncopyable
+  class TemporaryFile
   {
   private:
-    std::string  content_;
+    std::string path_;
 
   public:
-    void ReadFromFile(const std::string& filename);
+    TemporaryFile();
+
+    TemporaryFile(const char* extension);
+
+    ~TemporaryFile();
+
+    const std::string& GetPath() const
+    {
+      return path_;
+    }
 
-    void ReadFromMemory(const void* buffer,
-                        size_t size);
+    void Write(const std::string& content);
 
-    void ReadFromMemory(const std::string& buffer);
+    void Read(std::string& content) const;
   };
 }
diff --git a/Core/Toolbox.cpp b/Core/Toolbox.cpp
index 4990204..cb9bcb2 100644
--- a/Core/Toolbox.cpp
+++ b/Core/Toolbox.cpp
@@ -36,57 +36,31 @@
 #include "OrthancException.h"
 #include "Logging.h"
 
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/locale.hpp>
+#include <boost/uuid/sha1.hpp>
+
 #include <string>
 #include <stdint.h>
 #include <string.h>
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/uuid/sha1.hpp>
-#include <boost/lexical_cast.hpp>
 #include <algorithm>
 #include <ctype.h>
 
-#if BOOST_HAS_DATE_TIME == 1
-#include <boost/date_time/posix_time/posix_time.hpp>
-#endif
-
 #if BOOST_HAS_REGEX == 1
-#include <boost/regex.hpp> 
-#endif
-
-#if defined(_WIN32)
-#include <windows.h>
-#include <process.h>   // For "_spawnvp()" and "_getpid()"
-#else
-#include <unistd.h>    // For "execvp()"
-#include <sys/wait.h>  // For "waitpid()"
-#endif
-
-#if defined(__APPLE__) && defined(__MACH__)
-#include <mach-o/dyld.h> /* _NSGetExecutablePath */
-#include <limits.h>      /* PATH_MAX */
-#endif
-
-#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
-#include <limits.h>      /* PATH_MAX */
-#include <signal.h>
-#include <unistd.h>
+#  include <boost/regex.hpp> 
 #endif
 
 #if BOOST_HAS_LOCALE != 1
-#error Since version 0.7.6, Orthanc entirely relies on boost::locale
+#  error Since version 0.7.6, Orthanc entirely relies on boost::locale
 #endif
 
-#include <boost/locale.hpp>
-
-
-#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
-#include "../Resources/ThirdParty/md5/md5.h"
+#if ORTHANC_ENABLE_MD5 == 1
+#  include "../Resources/ThirdParty/md5/md5.h"
 #endif
 
-
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
-#include "../Resources/ThirdParty/base64/base64.h"
+#if ORTHANC_ENABLE_BASE64 == 1
+#  include "../Resources/ThirdParty/base64/base64.h"
 #endif
 
 
@@ -103,42 +77,24 @@ extern "C"
 #endif
 
 
-#if ORTHANC_PUGIXML_ENABLED == 1
-#include "ChunkedBuffer.h"
-#include <pugixml.hpp>
+#if defined(_WIN32)
+#  include <windows.h>   // For ::Sleep
 #endif
 
 
-namespace Orthanc
-{
-  static bool finish_;
-  static ServerBarrierEvent barrierEvent_;
-
-#if defined(_WIN32)
-  static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType)
-  {
-    // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx
-    finish_ = true;
-    return true;
-  }
-#else
-  static void SignalHandler(int signal)
-  {
-    if (signal == SIGHUP)
-    {
-      barrierEvent_ = ServerBarrierEvent_Reload;
-    }
-
-    finish_ = true;
-  }
+#if ORTHANC_ENABLE_PUGIXML == 1
+#  include "ChunkedBuffer.h"
+#  include <pugixml.hpp>
 #endif
 
 
+namespace Orthanc
+{
   void Toolbox::USleep(uint64_t microSeconds)
   {
 #if defined(_WIN32)
     ::Sleep(static_cast<DWORD>(microSeconds / static_cast<uint64_t>(1000)));
-#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__native_client__)
     usleep(microSeconds);
 #else
 #error Support your platform here
@@ -146,50 +102,6 @@ namespace Orthanc
   }
 
 
-  static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag)
-  {
-#if defined(_WIN32)
-    SetConsoleCtrlHandler(ConsoleControlHandler, true);
-#else
-    signal(SIGINT, SignalHandler);
-    signal(SIGQUIT, SignalHandler);
-    signal(SIGTERM, SignalHandler);
-    signal(SIGHUP, SignalHandler);
-#endif
-  
-    // Active loop that awakens every 100ms
-    finish_ = false;
-    barrierEvent_ = ServerBarrierEvent_Stop;
-    while (!(*stopFlag || finish_))
-    {
-      Toolbox::USleep(100 * 1000);
-    }
-
-#if defined(_WIN32)
-    SetConsoleCtrlHandler(ConsoleControlHandler, false);
-#else
-    signal(SIGINT, NULL);
-    signal(SIGQUIT, NULL);
-    signal(SIGTERM, NULL);
-    signal(SIGHUP, NULL);
-#endif
-
-    return barrierEvent_;
-  }
-
-
-  ServerBarrierEvent Toolbox::ServerBarrier(const bool& stopFlag)
-  {
-    return ServerBarrierInternal(&stopFlag);
-  }
-
-  ServerBarrierEvent Toolbox::ServerBarrier()
-  {
-    const bool stopFlag = false;
-    return ServerBarrierInternal(&stopFlag);
-  }
-
-
   void Toolbox::ToUpperCase(std::string& s)
   {
     std::transform(s.begin(), s.end(), s.begin(), toupper);
@@ -217,134 +129,6 @@ namespace Orthanc
   }
 
 
-  static std::streamsize GetStreamSize(std::istream& f)
-  {
-    // http://www.cplusplus.com/reference/iostream/istream/tellg/
-    f.seekg(0, std::ios::end);
-    std::streamsize size = f.tellg();
-    f.seekg(0, std::ios::beg);
-
-    return size;
-  }
-
-
-  void Toolbox::ReadFile(std::string& content,
-                         const std::string& path) 
-  {
-    if (!IsRegularFile(path))
-    {
-      LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
-      throw OrthancException(ErrorCode_RegularFileExpected);
-    }
-
-    boost::filesystem::ifstream f;
-    f.open(path, std::ifstream::in | std::ifstream::binary);
-    if (!f.good())
-    {
-      throw OrthancException(ErrorCode_InexistentFile);
-    }
-
-    std::streamsize size = GetStreamSize(f);
-    content.resize(size);
-    if (size != 0)
-    {
-      f.read(reinterpret_cast<char*>(&content[0]), size);
-    }
-
-    f.close();
-  }
-
-
-  bool Toolbox::ReadHeader(std::string& header,
-                           const std::string& path,
-                           size_t headerSize)
-  {
-    if (!IsRegularFile(path))
-    {
-      LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
-      throw OrthancException(ErrorCode_RegularFileExpected);
-    }
-
-    boost::filesystem::ifstream f;
-    f.open(path, std::ifstream::in | std::ifstream::binary);
-    if (!f.good())
-    {
-      throw OrthancException(ErrorCode_InexistentFile);
-    }
-
-    bool full = true;
-
-    {
-      std::streamsize size = GetStreamSize(f);
-      if (size <= 0)
-      {
-        headerSize = 0;
-        full = false;
-      }
-      else if (static_cast<size_t>(size) < headerSize)
-      {
-        headerSize = size;  // Truncate to the size of the file
-        full = false;
-      }
-    }
-
-    header.resize(headerSize);
-    if (headerSize != 0)
-    {
-      f.read(reinterpret_cast<char*>(&header[0]), headerSize);
-    }
-
-    f.close();
-
-    return full;
-  }
-
-
-  void Toolbox::WriteFile(const void* content,
-                          size_t size,
-                          const std::string& path)
-  {
-    boost::filesystem::ofstream f;
-    f.open(path, std::ofstream::binary);
-    if (!f.good())
-    {
-      throw OrthancException(ErrorCode_CannotWriteFile);
-    }
-
-    if (size != 0)
-    {
-      f.write(reinterpret_cast<const char*>(content), size);
-    }
-
-    f.close();
-  }
-
-
-  void Toolbox::WriteFile(const std::string& content,
-                          const std::string& path)
-  {
-    WriteFile(content.size() > 0 ? content.c_str() : NULL,
-              content.size(), path);
-  }
-
-
-  void Toolbox::RemoveFile(const std::string& path)
-  {
-    if (boost::filesystem::exists(path))
-    {
-      if (IsRegularFile(path))
-      {
-        boost::filesystem::remove(path);
-      }
-      else
-      {
-        throw OrthancException(ErrorCode_RegularFileExpected);
-      }
-    }
-  }
-
-
-
   void Toolbox::SplitUriComponents(UriComponents& components,
                                    const std::string& uri)
   {
@@ -512,21 +296,7 @@ namespace Orthanc
   }
 
 
-
-  uint64_t Toolbox::GetFileSize(const std::string& path)
-  {
-    try
-    {
-      return static_cast<uint64_t>(boost::filesystem::file_size(path));
-    }
-    catch (boost::filesystem::filesystem_error&)
-    {
-      throw OrthancException(ErrorCode_InexistentFile);
-    }
-  }
-
-
-#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
+#if ORTHANC_ENABLE_MD5 == 1
   static char GetHexadecimalCharacter(uint8_t value)
   {
     assert(value < 16);
@@ -583,7 +353,7 @@ namespace Orthanc
 #endif
 
 
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
   void Toolbox::EncodeBase64(std::string& result, 
                              const std::string& data)
   {
@@ -642,60 +412,6 @@ namespace Orthanc
 #endif
 
 
-
-#if defined(_WIN32)
-  static std::string GetPathToExecutableInternal()
-  {
-    // Yes, this is ugly, but there is no simple way to get the 
-    // required buffer size, so we use a big constant
-    std::vector<char> buffer(32768);
-    /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1));
-    return std::string(&buffer[0]);
-  }
-
-#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
-  static std::string GetPathToExecutableInternal()
-  {
-    std::vector<char> buffer(PATH_MAX + 1);
-    ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
-    if (bytes == 0)
-    {
-      throw OrthancException(ErrorCode_PathToExecutable);
-    }
-
-    return std::string(&buffer[0]);
-  }
-
-#elif defined(__APPLE__) && defined(__MACH__)
-  static std::string GetPathToExecutableInternal()
-  {
-    char pathbuf[PATH_MAX + 1];
-    unsigned int  bufsize = static_cast<int>(sizeof(pathbuf));
-
-    _NSGetExecutablePath( pathbuf, &bufsize);
-
-    return std::string(pathbuf);
-  }
-
-#else
-#error Support your platform here
-#endif
-
-
-  std::string Toolbox::GetPathToExecutable()
-  {
-    boost::filesystem::path p(GetPathToExecutableInternal());
-    return boost::filesystem::absolute(p).string();
-  }
-
-
-  std::string Toolbox::GetDirectoryOfExecutable()
-  {
-    boost::filesystem::path p(GetPathToExecutableInternal());
-    return boost::filesystem::absolute(p.parent_path()).string();
-  }
-
-
   static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding)
   {
     switch (sourceEncoding)
@@ -820,6 +536,23 @@ namespace Orthanc
   }
 
 
+  bool Toolbox::IsAsciiString(const void* data,
+                              size_t size)
+  {
+    const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+
+    for (size_t i = 0; i < size; i++, p++)
+    {
+      if (*p > 127 || (*p != 0 && iscntrl(*p)))
+      {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+
   std::string Toolbox::ConvertToAscii(const std::string& source)
   {
     std::string result;
@@ -956,30 +689,6 @@ namespace Orthanc
   }
 
 
-#if BOOST_HAS_DATE_TIME == 1
-  std::string Toolbox::GetNowIsoString()
-  {
-    boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
-    return boost::posix_time::to_iso_string(now);
-  }
-
-  void Toolbox::GetNowDicom(std::string& date,
-                            std::string& time)
-  {
-    boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
-    tm tm = boost::posix_time::to_tm(now);
-
-    char s[32];
-    sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
-    date.assign(s);
-
-    // TODO milliseconds
-    sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
-    time.assign(s);
-  }
-#endif
-
-
   std::string Toolbox::StripSpaces(const std::string& source)
   {
     size_t first = 0;
@@ -1137,32 +846,7 @@ namespace Orthanc
   }
 
 
-  void Toolbox::MakeDirectory(const std::string& path)
-  {
-    if (boost::filesystem::exists(path))
-    {
-      if (!boost::filesystem::is_directory(path))
-      {
-        throw OrthancException(ErrorCode_DirectoryOverFile);
-      }
-    }
-    else
-    {
-      if (!boost::filesystem::create_directories(path))
-      {
-        throw OrthancException(ErrorCode_MakeDirectory);
-      }
-    }
-  }
-
-
-  bool Toolbox::IsExistingFile(const std::string& path)
-  {
-    return boost::filesystem::exists(path);
-  }
-
-
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
   class ChunkedBufferWriter : public pugi::xml_writer
   {
   private:
@@ -1284,64 +968,6 @@ namespace Orthanc
 #endif
 
 
-  void Toolbox::ExecuteSystemCommand(const std::string& command,
-                                     const std::vector<std::string>& arguments)
-  {
-    // Convert the arguments as a C array
-    std::vector<char*>  args(arguments.size() + 2);
-
-    args.front() = const_cast<char*>(command.c_str());
-
-    for (size_t i = 0; i < arguments.size(); i++)
-    {
-      args[i + 1] = const_cast<char*>(arguments[i].c_str());
-    }
-
-    args.back() = NULL;
-
-    int status;
-
-#if defined(_WIN32)
-    // http://msdn.microsoft.com/en-us/library/275khfab.aspx
-    status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0]));
-
-#else
-    int pid = fork();
-
-    if (pid == -1)
-    {
-      // Error in fork()
-#if ORTHANC_ENABLE_LOGGING == 1
-      LOG(ERROR) << "Cannot fork a child process";
-#endif
-
-      throw OrthancException(ErrorCode_SystemCommand);
-    }
-    else if (pid == 0)
-    {
-      // Execute the system command in the child process
-      execvp(command.c_str(), &args[0]);
-
-      // We should never get here
-      _exit(1);
-    }
-    else
-    {
-      // Wait for the system command to exit
-      waitpid(pid, &status, 0);
-    }
-#endif
-
-    if (status != 0)
-    {
-#if ORTHANC_ENABLE_LOGGING == 1
-      LOG(ERROR) << "System command failed with status code " << status;
-#endif
-
-      throw OrthancException(ErrorCode_SystemCommand);
-    }
-  }
-
   
   bool Toolbox::IsInteger(const std::string& str)
   {
@@ -1449,64 +1075,6 @@ namespace Orthanc
       return str.compare(0, prefix.size(), prefix) == 0;
     }
   }
-
-
-  int Toolbox::GetProcessId()
-  {
-#if defined(_WIN32)
-    return static_cast<int>(_getpid());
-#else
-    return static_cast<int>(getpid());
-#endif
-  }
-
-
-  bool Toolbox::IsRegularFile(const std::string& path)
-  {
-    namespace fs = boost::filesystem;
-
-    try
-    {
-      if (fs::exists(path))
-      {
-        fs::file_status status = fs::status(path);
-        return (status.type() == boost::filesystem::regular_file ||
-                status.type() == boost::filesystem::reparse_file);   // Fix BitBucket issue #11
-      }
-    }
-    catch (fs::filesystem_error&)
-    {
-    }
-
-    return false;
-  }
-
-
-  FILE* Toolbox::OpenFile(const std::string& path,
-                          FileMode mode)
-  {
-#if defined(_WIN32)
-    // TODO Deal with special characters by converting to the current locale
-#endif
-
-    const char* m;
-    switch (mode)
-    {
-      case FileMode_ReadBinary:
-        m = "rb";
-        break;
-
-      case FileMode_WriteBinary:
-        m = "wb";
-        break;
-
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    return fopen(path.c_str(), m);
-  }
-
   
 
   static bool IsUnreservedCharacter(char c)
@@ -1564,5 +1132,134 @@ namespace Orthanc
         target.push_back(b < 10 ? b + '0' : b - 10 + 'A');
       }
     }
-  }  
+  }
+
+
+  static bool HasField(const Json::Value& json,
+                       const std::string& key,
+                       Json::ValueType expectedType)
+  {
+    if (json.type() != Json::objectValue ||
+        !json.isMember(key))
+    {
+      return false;
+    }
+    else if (json[key].type() == expectedType)
+    {
+      return true;
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+  }
+
+
+  std::string Toolbox::GetJsonStringField(const Json::Value& json,
+                                          const std::string& key,
+                                          const std::string& defaultValue)
+  {
+    if (HasField(json, key, Json::stringValue))
+    {
+      return json[key].asString();
+    }
+    else
+    {
+      return defaultValue;
+    }
+  }
+
+
+  bool Toolbox::GetJsonBooleanField(const ::Json::Value& json,
+                                    const std::string& key,
+                                    bool defaultValue)
+  {
+    if (HasField(json, key, Json::booleanValue))
+    {
+      return json[key].asBool();
+    }
+    else
+    {
+      return defaultValue;
+    }
+  }
+
+
+  int Toolbox::GetJsonIntegerField(const ::Json::Value& json,
+                                   const std::string& key,
+                                   int defaultValue)
+  {
+    if (HasField(json, key, Json::intValue))
+    {
+      return json[key].asInt();
+    }
+    else
+    {
+      return defaultValue;
+    }
+  }
+
+
+  unsigned int Toolbox::GetJsonUnsignedIntegerField(const ::Json::Value& json,
+                                                    const std::string& key,
+                                                    unsigned int defaultValue)
+  {
+    int v = GetJsonIntegerField(json, key, defaultValue);
+
+    if (v < 0)
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      return static_cast<unsigned int>(v);
+    }
+  }
+
+
+  bool Toolbox::IsUuid(const std::string& str)
+  {
+    if (str.size() != 36)
+    {
+      return false;
+    }
+
+    for (size_t i = 0; i < str.length(); i++)
+    {
+      if (i == 8 || i == 13 || i == 18 || i == 23)
+      {
+        if (str[i] != '-')
+          return false;
+      }
+      else
+      {
+        if (!isalnum(str[i]))
+          return false;
+      }
+    }
+
+    return true;
+  }
+
+
+  bool Toolbox::StartsWithUuid(const std::string& str)
+  {
+    if (str.size() < 36)
+    {
+      return false;
+    }
+
+    if (str.size() == 36)
+    {
+      return IsUuid(str);
+    }
+
+    assert(str.size() > 36);
+    if (!isspace(str[36]))
+    {
+      return false;
+    }
+
+    return IsUuid(str.substr(0, 36));
+  }
 }
diff --git a/Core/Toolbox.h b/Core/Toolbox.h
index cb67473..d32777a 100644
--- a/Core/Toolbox.h
+++ b/Core/Toolbox.h
@@ -39,6 +39,35 @@
 #include <string>
 #include <json/json.h>
 
+
+#if !defined(ORTHANC_ENABLE_BASE64)
+#  error The macro ORTHANC_ENABLE_BASE64 must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_MD5)
+#  error The macro ORTHANC_ENABLE_MD5 must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_PUGIXML)
+#  error The macro ORTHANC_ENABLE_PUGIXML must be defined
+#endif
+
+#if !defined(BOOST_HAS_REGEX)
+#  error The macro BOOST_HAS_REGEX must be defined
+#endif
+
+
+/**
+ * NOTE: GUID vs. UUID
+ * The simple answer is: no difference, they are the same thing. Treat
+ * them as a 16 byte (128 bits) value that is used as a unique
+ * value. In Microsoft-speak they are called GUIDs, but call them
+ * UUIDs when not using Microsoft-speak.
+ * http://stackoverflow.com/questions/246930/is-there-any-difference-between-a-guid-and-a-uuid
+ **/
+
+
+
 namespace Orthanc
 {
   typedef std::vector<std::string> UriComponents;
@@ -49,9 +78,7 @@ namespace Orthanc
 
   namespace Toolbox
   {
-    ServerBarrierEvent ServerBarrier(const bool& stopFlag);
-
-    ServerBarrierEvent ServerBarrier();
+    void USleep(uint64_t microSeconds);
 
     void ToUpperCase(std::string& s);  // Inplace version
 
@@ -63,24 +90,6 @@ namespace Orthanc
     void ToLowerCase(std::string& result,
                      const std::string& source);
 
-    void ReadFile(std::string& content,
-                  const std::string& path);
-
-    bool ReadHeader(std::string& header,
-                    const std::string& path,
-                    size_t headerSize);
-
-    void WriteFile(const std::string& content,
-                   const std::string& path);
-
-    void WriteFile(const void* content,
-                   size_t size,
-                   const std::string& path);
-
-    void USleep(uint64_t microSeconds);
-
-    void RemoveFile(const std::string& path);
-
     void SplitUriComponents(UriComponents& components,
                             const std::string& uri);
   
@@ -96,9 +105,7 @@ namespace Orthanc
     std::string FlattenUri(const UriComponents& components,
                            size_t fromLevel = 0);
 
-    uint64_t GetFileSize(const std::string& path);
-
-#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
+#if ORTHANC_ENABLE_MD5 == 1
     void ComputeMD5(std::string& result,
                     const std::string& data);
 
@@ -119,7 +126,7 @@ namespace Orthanc
 
     bool IsSHA1(const std::string& s);
 
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
     void DecodeBase64(std::string& result, 
                       const std::string& data);
 
@@ -137,27 +144,19 @@ namespace Orthanc
                              const std::string& content);
 #endif
 
-    std::string GetPathToExecutable();
-
-    std::string GetDirectoryOfExecutable();
-
     std::string ConvertToUtf8(const std::string& source,
                               Encoding sourceEncoding);
 
     std::string ConvertFromUtf8(const std::string& source,
                                 Encoding targetEncoding);
 
+    bool IsAsciiString(const void* data,
+                       size_t size);
+
     std::string ConvertToAscii(const std::string& source);
 
     std::string StripSpaces(const std::string& source);
 
-#if BOOST_HAS_DATE_TIME == 1
-    std::string GetNowIsoString();
-
-    void GetNowDicom(std::string& date,
-                     std::string& time);
-#endif
-
     // In-place percent-decoding for URL
     void UrlDecode(std::string& s);
 
@@ -171,20 +170,13 @@ namespace Orthanc
                         const std::string& source,
                         char separator);
 
-    void MakeDirectory(const std::string& path);
-
-    bool IsExistingFile(const std::string& path);
-
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
     void JsonToXml(std::string& target,
                    const Json::Value& source,
                    const std::string& rootElement = "root",
                    const std::string& arrayElement = "item");
 #endif
 
-    void ExecuteSystemCommand(const std::string& command,
-                              const std::vector<std::string>& arguments);
-
     bool IsInteger(const std::string& str);
 
     void CopyJsonWithoutComments(Json::Value& target,
@@ -193,14 +185,27 @@ namespace Orthanc
     bool StartsWith(const std::string& str,
                     const std::string& prefix);
 
-    int GetProcessId();
+    void UriEncode(std::string& target,
+                   const std::string& source);
+
+    std::string GetJsonStringField(const ::Json::Value& json,
+                                   const std::string& key,
+                                   const std::string& defaultValue);
 
-    bool IsRegularFile(const std::string& path);
+    bool GetJsonBooleanField(const ::Json::Value& json,
+                             const std::string& key,
+                             bool defaultValue);
 
-    FILE* OpenFile(const std::string& path,
-                   FileMode mode);
+    int GetJsonIntegerField(const ::Json::Value& json,
+                            const std::string& key,
+                            int defaultValue);
 
-    void UriEncode(std::string& target,
-                   const std::string& source);
+    unsigned int GetJsonUnsignedIntegerField(const ::Json::Value& json,
+                                             const std::string& key,
+                                             unsigned int defaultValue);
+
+    bool IsUuid(const std::string& str);
+
+    bool StartsWithUuid(const std::string& str);
   }
 }
diff --git a/Core/Uuid.cpp b/Core/Uuid.cpp
deleted file mode 100644
index 8681095..0000000
--- a/Core/Uuid.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- * 
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "PrecompiledHeaders.h"
-#include "Uuid.h"
-
-// http://stackoverflow.com/a/1626302
-
-extern "C"
-{
-#ifdef WIN32
-#include <rpc.h>
-#else
-#include <uuid/uuid.h>
-#endif
-}
-
-#include <boost/filesystem.hpp>
-
-namespace Orthanc
-{
-  namespace Toolbox
-  {
-    std::string GenerateUuid()
-    {
-#ifdef WIN32
-      UUID uuid;
-      UuidCreate ( &uuid );
-
-      unsigned char * str;
-      UuidToStringA ( &uuid, &str );
-
-      std::string s( ( char* ) str );
-
-      RpcStringFreeA ( &str );
-#else
-      uuid_t uuid;
-      uuid_generate_random ( uuid );
-      char s[37];
-      uuid_unparse ( uuid, s );
-#endif
-      return s;
-    }
-
-
-    bool IsUuid(const std::string& str)
-    {
-      if (str.size() != 36)
-      {
-        return false;
-      }
-
-      for (size_t i = 0; i < str.length(); i++)
-      {
-        if (i == 8 || i == 13 || i == 18 || i == 23)
-        {
-          if (str[i] != '-')
-            return false;
-        }
-        else
-        {
-          if (!isalnum(str[i]))
-            return false;
-        }
-      }
-
-      return true;
-    }
-
-
-    bool StartsWithUuid(const std::string& str)
-    {
-      if (str.size() < 36)
-      {
-        return false;
-      }
-
-      if (str.size() == 36)
-      {
-        return IsUuid(str);
-      }
-
-      assert(str.size() > 36);
-      if (!isspace(str[36]))
-      {
-        return false;
-      }
-
-      return IsUuid(str.substr(0, 36));
-    }
-
-
-    static std::string CreateTemporaryPath(const char* extension)
-    {
-#if BOOST_HAS_FILESYSTEM_V3 == 1
-      boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path();
-#elif defined(__linux__)
-      boost::filesystem::path tmpDir("/tmp");
-#else
-#error Support your platform here
-#endif
-
-      // We use UUID to create unique path to temporary files
-      std::string filename = "Orthanc-" + Orthanc::Toolbox::GenerateUuid();
-
-      if (extension != NULL)
-      {
-        filename.append(extension);
-      }
-
-      tmpDir /= filename;
-      return tmpDir.string();
-    }
-
-
-    TemporaryFile::TemporaryFile() : 
-      path_(CreateTemporaryPath(NULL))
-    {
-    }
-
-
-    TemporaryFile::TemporaryFile(const char* extension) :
-      path_(CreateTemporaryPath(extension))
-    {
-    }
-
-
-    TemporaryFile::~TemporaryFile()
-    {
-      boost::filesystem::remove(path_);
-    }  
-  }
-}
diff --git a/Core/WebServiceParameters.cpp b/Core/WebServiceParameters.cpp
index 52e0ea6..cef2e26 100644
--- a/Core/WebServiceParameters.cpp
+++ b/Core/WebServiceParameters.cpp
@@ -37,6 +37,10 @@
 #include "../Core/Toolbox.h"
 #include "../Core/OrthancException.h"
 
+#if ORTHANC_SANDBOXED == 0
+#  include "../Core/SystemToolbox.h"
+#endif
+
 #include <cassert>
 
 namespace Orthanc
@@ -57,6 +61,7 @@ namespace Orthanc
   }
 
 
+#if ORTHANC_SANDBOXED == 0
   void WebServiceParameters::SetClientCertificate(const std::string& certificateFile,
                                                   const std::string& certificateKeyFile,
                                                   const std::string& certificateKeyPassword)
@@ -66,14 +71,14 @@ namespace Orthanc
       throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
 
-    if (!Toolbox::IsRegularFile(certificateFile))
+    if (!SystemToolbox::IsRegularFile(certificateFile))
     {
       LOG(ERROR) << "Cannot open certificate file: " << certificateFile;
       throw OrthancException(ErrorCode_InexistentFile);
     }
 
     if (!certificateKeyFile.empty() && 
-        !Toolbox::IsRegularFile(certificateKeyFile))
+        !SystemToolbox::IsRegularFile(certificateKeyFile))
     {
       LOG(ERROR) << "Cannot open key file: " << certificateKeyFile;
       throw OrthancException(ErrorCode_InexistentFile);
@@ -84,6 +89,7 @@ namespace Orthanc
     certificateKeyFile_ = certificateKeyFile;
     certificateKeyPassword_ = certificateKeyPassword;
   }
+#endif
 
 
   static void AddTrailingSlash(std::string& url)
@@ -171,12 +177,14 @@ namespace Orthanc
     SetUsername(GetStringMember(peer, "Username", ""));
     SetPassword(GetStringMember(peer, "Password", ""));
 
+#if ORTHANC_SANDBOXED == 0
     if (peer.isMember("CertificateFile"))
     {
       SetClientCertificate(GetStringMember(peer, "CertificateFile", ""),
                            GetStringMember(peer, "CertificateKeyFile", ""),
                            GetStringMember(peer, "CertificateKeyPassword", ""));
     }
+#endif
 
     if (peer.isMember("Pkcs11"))
     {
diff --git a/Core/WebServiceParameters.h b/Core/WebServiceParameters.h
index 40d6cf9..b6b373f 100644
--- a/Core/WebServiceParameters.h
+++ b/Core/WebServiceParameters.h
@@ -32,6 +32,10 @@
 
 #pragma once
 
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
 #include <string>
 #include <json/json.h>
 
@@ -88,9 +92,11 @@ namespace Orthanc
 
     void ClearClientCertificate();
 
+#if ORTHANC_SANDBOXED == 0
     void SetClientCertificate(const std::string& certificateFile,
                               const std::string& certificateKeyFile,
                               const std::string& certificateKeyPassword);
+#endif
 
     const std::string& GetCertificateFile() const
     {
diff --git a/DarwinCompilation.txt b/DarwinCompilation.txt
index 2e584a2..62244d7 100644
--- a/DarwinCompilation.txt
+++ b/DarwinCompilation.txt
@@ -31,7 +31,9 @@ Prepare the build with CMake
 # cmake -GXcode -DCMAKE_OSX_DEPLOYMENT_TARGET=10.8 -DSTATIC_BUILD=ON -DSTANDALONE_BUILD=ON -DALLOW_DOWNLOADS=ON ~/Orthanc
 
 NB: Adapt the value of "CMAKE_OSX_DEPLOYMENT_TARGET" with respect to
-your version of XCode.
+your version of OS X. This version can obtained by typing:
+
+# sw_vers
 
 
 Build the Debug version of Orthanc
@@ -47,6 +49,6 @@ Build the Release version of Orthanc
 ------------------------------------
 
 # xcodebuild -configuration Release
-# ./Debug/UnitTests
+# ./Release/UnitTests
 
 The binaries of Orthanc are located at "~/OrthancBuild/Release/Orthanc".
diff --git a/INSTALL b/INSTALL
index be97597..33762ab 100644
--- a/INSTALL
+++ b/INSTALL
@@ -51,12 +51,17 @@ WARNING 2: If cmake complains about not being able to uncompress
 third-party dependencies, delete the "~/Orthanc/ThirdPartyDownloads/"
 folder, then restart cmake.
 
+WARNING 3: If performance is important to you, make sure to add the
+option "-DCMAKE_BUILD_TYPE=Release" when invoking cmake. Indeed, by
+default, run-time debug assertions are enabled, which can seriously
+impact performance, especially if your Orthanc server stores a lot of
+DICOM instances.
 
-Native Linux Compilation
-------------------------
 
-See the file "LinuxCompilation.txt".
+Native GNU/Linux Compilation
+----------------------------
 
+See the file "LinuxCompilation.txt".
 
 
 Native OS X Compilation
@@ -85,8 +90,8 @@ NOTES:
 
 
 
-Cross-Compilation for Windows under Linux
------------------------------------------
+Cross-Compilation for Windows under GNU/Linux
+---------------------------------------------
 
 To cross-compile Windows binaries under Linux using MinGW, please use
 the following command:
diff --git a/LinuxCompilation.txt b/LinuxCompilation.txt
index 15e7bb2..8c075cb 100644
--- a/LinuxCompilation.txt
+++ b/LinuxCompilation.txt
@@ -1,17 +1,17 @@
 This file is a complement to "INSTALL", which contains instructions
-that are specific to Linux.
+that are specific to GNU/Linux.
 
 
-Static linking for Linux
-========================
+Static linking for GNU/Linux
+============================
 
-The most simple way of building Orthanc under Linux consists in
+The most simple way of building Orthanc under GNU/Linux consists in
 statically linking against all the third-party dependencies. In this
 case, the system-wide libraries will not be used. The build tool
 (CMake) will download the sources of all the required packages and
 automatically compile them.
 
-This process should work on any Linux distribution, provided that a
+This process should work on any GNU/Linux distribution, provided that a
 C/C++ compiler ("build-essential" in Debian-based systems), the Python
 interpreter, CMake, the "unzip" system tool, and the development
 package for libuuid ("uuid-dev" in Debian) are installed.
@@ -47,14 +47,14 @@ then run cmake again.
 Note 3- To build the documentation, you will have to install doxyen.
 
 
-Use system-wide libraries under Linux
-=====================================
+Use system-wide libraries under GNU/Linux
+=========================================
 
-Under Linux, by default, Orthanc links against the shared libraries of
-your system (the "STATIC_BUILD" option is set to "OFF"). This greatly
-speeds up the compilation. This is also required when building
-packages for Linux distributions. Because using system libraries is
-the default behavior, you just have to use:
+Under GNU/Linux, by default, Orthanc links against the shared
+libraries of your system (the "STATIC_BUILD" option is set to
+"OFF"). This greatly speeds up the compilation. This is also required
+when building packages for GNU/Linux distributions. Because using
+system libraries is the default behavior, you just have to use:
 
 # cd ~/OrthancBuild
 # cmake -DCMAKE_BUILD_TYPE=Debug ~/Orthanc
@@ -62,13 +62,14 @@ the default behavior, you just have to use:
 
 Note that to build the documentation, you will have to install doxyen.
 
-However, on some Linux distributions, it is still required to download
-and static link against some third-party dependencies, e.g. when the
-system-wide library is not shipped or is outdated. Because of
-difference in the packaging of the various Linux distribution, it is
-also sometimes required to fine-tune some options.
+However, on some GNU/Linux distributions, it is still required to
+download and static link against some third-party dependencies,
+e.g. when the system-wide library is not shipped or is
+outdated. Because of difference in the packaging of the various
+GNU/Linux distribution, it is also sometimes required to fine-tune
+some options.
 
-You will find below build instructions for specific Linux
+You will find below build instructions for specific GNU/Linux
 distributions. Distributions tagged by "SUPPORTED" are tested by
 Sébastien Jodogne. Distributions tagged by "CONTRIBUTED" come from
 Orthanc users.
@@ -183,8 +184,8 @@ SUPPORTED - CentOS 6
 
 
 
-Other Linux distributions?
---------------------------
+Other GNU/Linux distributions?
+------------------------------
 
 Please send us your build instructions (by a mail to
 s.jodogne at gmail.com)!
@@ -202,7 +203,7 @@ they might give indications.
 Using ccache
 ============
 
-Under Linux, you also have the opportunity to use "ccache" to
+Under GNU/Linux, you also have the opportunity to use "ccache" to
 dramatically decrease the compilation time when rebuilding
 Orthanc. This is especially useful for developers. To this end, you
 would use:
diff --git a/NEWS b/NEWS
index ffb4f7a..16a0800 100644
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,58 @@ Pending changes in the mainline
 ===============================
 
 
-Version 1.1.0 (2016/07/27)
+Version 1.2.0 (2016/12/13)
+==========================
+
+General
+-------
+
+* Handling of private tags/creators in the "Dictionary" configuration option
+* New configuration options: "LoadPrivateDictionary", "DicomScuTimeout" and "DicomScpTimeout"
+* New metadata automatically computed at the instance level: "TransferSyntax" and "SopClassUid"
+
+REST API
+--------
+
+* "/tools/invalidate-tags" to invalidate the JSON summary of all the DICOM files
+  (useful if private tags are registered, or if changing the default encoding)
+* "Permissive" flag for URI "/modalities/{...}/store" to ignore C-STORE transfer errors
+* "Asynchronous" flag for URIs "/modalities/{...}/store" and "/peers/{...}/store"
+  to avoid waiting for the completion of image transfers
+* Possibility to DELETE "dicom-as-json" attachments to reconstruct the JSON summaries
+  (useful if "Dictionary" has changed)
+* "Keep" option for modifications to keep original DICOM identifiers (advanced feature)
+* "/tools/default-encoding" to get or temporarily change the default encoding
+* "/{resource}/{id}/reconstruct" to reconstruct the main DICOM tags, the JSON summary and
+  the metadata of a resource (useful to compute new metadata, or if using "Keep" above)
+
+Plugins
+-------
+
+* New function: "OrthancPluginRegisterPrivateDictionaryTag()" to register private tags
+* More control over client cache in the ServeFolders plugin
+* New C++ help wrappers in "Plugins/Samples/Common/" to read DICOM datasets from REST API
+* New data structure: "OrthancPluginFindMatcher" to match DICOM against C-FIND queries
+
+Maintenance
+-----------
+
+* Fix handling of encodings in C-FIND requests (including for worklists)
+* Use of DCMTK 3.6.1 dictionary of private tags in standalone builds
+* Avoid hard crash if not enough memory (handling of std::bad_alloc)
+* Improved robustness of Orthanc Explorer wrt. query/retrieve (maybe fix issue 24)
+* Fix serious performance issue with C-FIND
+* Fix extraction of the symbolic name of the private tags
+* Performance warning if runtime debug assertions are turned on
+* Improved robustness against files with no PatientID
+* Upgrade to curl 7.50.3 for static and Windows builds
+* Content-Type for JSON documents is now "application/json; charset=utf-8"
+* Ignore "Group Length" tags in C-FIND queries
+* Fix handling of worklist SCP with ReferencedStudySequence and ReferencedPatientSequence
+* Fix handling of Move Originator AET and ID in C-MOVE SCP
+
+
+Version 1.1.0 (2016/06/27)
 ==========================
 
 General
@@ -17,23 +68,23 @@ REST API
 --------
 
 * New URI: "/instances/.../frames/.../raw" to access the raw frames (bypass image decoding)
-* New URI "/modalities/.../move" to issue C-Move SCU requests
+* New URI "/modalities/.../move" to issue C-MOVE SCU requests
 * "MoveOriginatorID" can be specified for "/modalities/.../store"
 
 Dicom protocol
 --------------
 
-* Support of optional tags for counting resources in C-Find:
+* Support of optional tags for counting resources in C-FIND:
   0008-0061, 0008-0062, 0020-1200, 0020-1202, 0020-1204, 0020-1206, 0020-1208, 0020-1209
-* Support of Move Originator Message ID (0000,1031) in C-Store responses driven by C-Move
+* Support of Move Originator Message ID (0000,1031) in C-STORE responses driven by C-MOVE
 
 Plugins
 -------
 
 * Speedup in plugins by removing unnecessary locks
 * New callback to filter incoming HTTP requests: OrthancPluginRegisterIncomingHttpRequestFilter()
-* New callback to handle non-worklists C-Find requests: OrthancPluginRegisterFindCallback()
-* New callback to handle C-Move requests: OrthancPluginRegisterMoveCallback()
+* New callback to handle non-worklists C-FIND requests: OrthancPluginRegisterFindCallback()
+* New callback to handle C-MOVE requests: OrthancPluginRegisterMoveCallback()
 * New function: "OrthancPluginHttpClient()" to do HTTP requests with full control
 * New function: "OrthancPluginGenerateUuid()" to generate a UUID
 * More than one custom image decoder can be installed (e.g. to handle different transfer syntaxes)
@@ -41,6 +92,7 @@ Plugins
 Lua
 ---
 
+* Possibility to dynamically fix outgoing C-FIND requests using "OutgoingFindRequestFilter()"
 * Access to the HTTP headers in the "IncomingHttpRequestFilter()" callback
 
 Image decoding
@@ -75,7 +127,7 @@ Maintenance
 Version 1.0.0 (2015/12/15)
 ==========================
 
-* Lua: "IncomingFindRequestFilter()" to apply filters to incoming C-Find requests
+* Lua: "IncomingFindRequestFilter()" to apply filters to incoming C-FIND requests
 * New function in plugin SDK: "OrthancPluginSendMultipartItem2()"
 * Fix of DICOMDIR generation with DCMTK 3.6.1, support of encodings
 * Fix range search if the lower or upper limit is absent
@@ -296,7 +348,7 @@ Fixes
 -----
 
 * Prevent freeze on C-FIND if no DICOM tag is to be returned
-* Fix slow C-STORE SCP on recent versions of Linux, if
+* Fix slow C-STORE SCP on recent versions of GNU/Linux, if
   USE_SYSTEM_DCMTK is set to OFF (http://forum.dcmtk.org/viewtopic.php?f=1&t=4009)
 * Fix issue 30 (QR response missing "Query/Retrieve Level" (008,0052))
 * Fix issue 32 (Cyrillic symbols): Introduction of the "Windows1251" encoding
@@ -517,8 +569,8 @@ Minor changes
 * Possibility to disable the HTTP server or the DICOM server
 * Automatic computation of MD5 hashes for the stored DICOM files
 * Maintenance tool to recover DICOM files compressed by Orthanc
-* The newline characters in the configuration file are fixed for Linux
-* Capture of the SIGTERM signal in Linux
+* The newline characters in the configuration file are fixed for GNU/Linux
+* Capture of the SIGTERM signal in GNU/Linux
 
 
 Version 0.7.2 (2013/11/08)
diff --git a/OrthancExplorer/explorer.html b/OrthancExplorer/explorer.html
index 90c61cf..fa3d77d 100644
--- a/OrthancExplorer/explorer.html
+++ b/OrthancExplorer/explorer.html
@@ -302,7 +302,7 @@
 
     <div data-role="page" id="query-retrieve" >
       <div data-role="header" >
-	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (1/3)</h1>
+	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (1/4)</h1>
         <a href="#find-patients" data-icon="home" class="ui-btn-left" data-direction="reverse">Patients</a>
       </div>
       <div data-role="content">
@@ -368,7 +368,7 @@
 
     <div data-role="page" id="query-retrieve-2" >
       <div data-role="header" >
-	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (2/3)</h1>
+	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (2/4)</h1>
         <a href="#find-patients" data-icon="home" class="ui-btn-left" data-direction="reverse">Patients</a>
         <a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
       </div>
@@ -381,17 +381,43 @@
 
     <div data-role="page" id="query-retrieve-3" >
       <div data-role="header" >
-	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (3/3)</h1>
+	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (3/4)</h1>
         <a href="#find-patients" data-icon="home" class="ui-btn-left" data-direction="reverse">Patients</a>
         <a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
       </div>
       <div data-role="content">
-        <ul data-role="listview" data-inset="true" data-filter="true" data-split-icon="arrow-d" data-split-theme="b">
+        <ul data-role="listview" data-inset="true" data-filter="true">
         </ul>
       </div>
     </div>
 
 
+    <div data-role="page" id="query-retrieve-4" >
+      <div data-role="header" >
+	<h1><span class="orthanc-name"></span>DICOM Query/Retrieve (4/4)</h1>
+        <a href="#find-patients" data-icon="home" class="ui-btn-left" data-direction="reverse">Patients</a>
+        <a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
+      </div>
+
+      <div data-role="content">
+        <form data-ajax="false" id="retrieve-form">
+          <div data-role="fieldcontain">
+	    <label for="retrieve-target">Target AET:</label>
+            <input type="text" name="retrieve-target" id="retrieve-target"></input>
+	  </div>
+
+          <fieldset class="ui-grid-b">
+	    <div class="ui-block-a"></div>
+	    <div class="ui-block-b">
+              <button id="retrieve-submit" type="submit" data-theme="b">Retrieve</button>
+            </div>
+	    <div class="ui-block-c"></div>
+	  </fieldset>
+        </form>
+      </div>
+    </div>
+
+
     <div id="peer-store" style="display:none;" class="ui-body-c">
       <p align="center"><b>Sending to Orthanc peer...</b></p>
       <p><img src="libs/images/ajax-loader.gif" alt="" /></p>
diff --git a/OrthancExplorer/explorer.js b/OrthancExplorer/explorer.js
index a1b130b..4d70a7b 100644
--- a/OrthancExplorer/explorer.js
+++ b/OrthancExplorer/explorer.js
@@ -30,6 +30,36 @@ String.prototype.format = function() {
 };
 
 
+function DeepCopy(obj)
+{
+  return jQuery.extend(true, {}, obj);
+}
+
+
+function ChangePage(page, options)
+{
+  var first = true;
+  if (options) {
+    for (var key in options) {
+      var value = options[key];
+      if (first) {
+        page += '?';
+        first = false;
+      } else {
+        page += '&';
+      }
+      
+      page += key + '=' + value;
+    }
+  }
+
+  window.location.replace('explorer.html#' + page);
+  /*$.mobile.changePage('#' + page, {
+    changeHash: true
+  });*/
+}
+
+
 function Refresh()
 {
   if (currentPage == 'patient')
@@ -369,8 +399,10 @@ function SetupAnonymizedOrModifiedFrom(buttonSelector, resource, resourceType, f
 function RefreshPatient()
 {
   if ($.mobile.pageData) {
-    GetResource('/patients/' + $.mobile.pageData.uuid, function(patient) {
-      GetResource('/patients/' + $.mobile.pageData.uuid + '/studies', function(studies) {
+    var pageData = DeepCopy($.mobile.pageData);
+
+    GetResource('/patients/' + pageData.uuid, function(patient) {
+      GetResource('/patients/' + pageData.uuid + '/studies', function(studies) {
         SortOnDicomTag(studies, 'StudyDate', false, true);
 
         $('#patient-info li').remove();
@@ -399,7 +431,7 @@ function RefreshPatient()
 
         // Check whether this patient is protected
         $.ajax({
-          url: '../patients/' + $.mobile.pageData.uuid + '/protected',
+          url: '../patients/' + pageData.uuid + '/protected',
           type: 'GET',
           dataType: 'text',
           async: false,
@@ -411,7 +443,7 @@ function RefreshPatient()
         });
 
         currentPage = 'patient';
-        currentUuid = $.mobile.pageData.uuid;
+        currentUuid = pageData.uuid;
       });
     });
   }
@@ -421,9 +453,11 @@ function RefreshPatient()
 function RefreshStudy()
 {
   if ($.mobile.pageData) {
-    GetResource('/studies/' + $.mobile.pageData.uuid, function(study) {
+    var pageData = DeepCopy($.mobile.pageData);
+
+    GetResource('/studies/' + pageData.uuid, function(study) {
       GetResource('/patients/' + study.ParentPatient, function(patient) {
-        GetResource('/studies/' + $.mobile.pageData.uuid + '/series', function(series) {
+        GetResource('/studies/' + pageData.uuid + '/series', function(series) {
           SortOnDicomTag(series, 'SeriesDate', false, true);
 
           $('#study .patient-link').attr('href', '#patient?uuid=' + patient.ID);
@@ -451,7 +485,7 @@ function RefreshStudy()
           target.listview('refresh');
 
           currentPage = 'study';
-          currentUuid = $.mobile.pageData.uuid;
+          currentUuid = pageData.uuid;
         });
       });
     });
@@ -462,10 +496,12 @@ function RefreshStudy()
 function RefreshSeries() 
 {
   if ($.mobile.pageData) {
-    GetResource('/series/' + $.mobile.pageData.uuid, function(series) {
+    var pageData = DeepCopy($.mobile.pageData);
+
+    GetResource('/series/' + pageData.uuid, function(series) {
       GetResource('/studies/' + series.ParentStudy, function(study) {
         GetResource('/patients/' + study.ParentPatient, function(patient) {
-          GetResource('/series/' + $.mobile.pageData.uuid + '/instances', function(instances) {
+          GetResource('/series/' + pageData.uuid + '/instances', function(instances) {
             Sort(instances, function(x) { return x.IndexInSeries; }, true, false);
 
             $('#series .patient-link').attr('href', '#patient?uuid=' + patient.ID);
@@ -492,7 +528,7 @@ function RefreshSeries()
             target.listview('refresh');
 
             currentPage = 'series';
-            currentUuid = $.mobile.pageData.uuid;
+            currentUuid = pageData.uuid;
           });
         });
       });
@@ -556,7 +592,9 @@ function ConvertForTree(dicom)
 function RefreshInstance()
 {
   if ($.mobile.pageData) {
-    GetResource('/instances/' + $.mobile.pageData.uuid, function(instance) {
+    var pageData = DeepCopy($.mobile.pageData);
+
+    GetResource('/instances/' + pageData.uuid, function(instance) {
       GetResource('/series/' + instance.ParentSeries, function(series) {
         GetResource('/studies/' + series.ParentStudy, function(study) {
           GetResource('/patients/' + study.ParentPatient, function(patient) {
@@ -585,7 +623,7 @@ function RefreshInstance()
             SetupAnonymizedOrModifiedFrom('#instance-modified-from', instance, 'instance', 'ModifiedFrom');
 
             currentPage = 'instance';
-            currentUuid = $.mobile.pageData.uuid;
+            currentUuid = pageData.uuid;
           });
         });
       });
@@ -704,7 +742,9 @@ $('#instance-download-json').live('click', function(e) {
 
 $('#instance-preview').live('click', function(e) {
   if ($.mobile.pageData) {
-    var pdf = '../instances/' + $.mobile.pageData.uuid + '/pdf';
+    var pageData = DeepCopy($.mobile.pageData);
+
+    var pdf = '../instances/' + pageData.uuid + '/pdf';
     $.ajax({
       url: pdf,
       cache: false,
@@ -712,11 +752,11 @@ $('#instance-preview').live('click', function(e) {
         window.location.assign(pdf);
       },
       error: function() {
-        GetResource('/instances/' + $.mobile.pageData.uuid + '/frames', function(frames) {
+        GetResource('/instances/' + pageData.uuid + '/frames', function(frames) {
           if (frames.length == 1)
           {
             // Viewing a single-frame image
-            jQuery.slimbox('../instances/' + $.mobile.pageData.uuid + '/preview', '', {
+            jQuery.slimbox('../instances/' + pageData.uuid + '/preview', '', {
               overlayFadeDuration : 1,
               resizeDuration : 1,
               imageFadeDuration : 1
@@ -728,7 +768,7 @@ $('#instance-preview').live('click', function(e) {
 
             var images = [];
             for (var i = 0; i < frames.length; i++) {
-              images.push([ '../instances/' + $.mobile.pageData.uuid + '/frames/' + i + '/preview' ]);
+              images.push([ '../instances/' + pageData.uuid + '/frames/' + i + '/preview' ]);
             }
 
             jQuery.slimbox(images, 0, {
@@ -748,8 +788,10 @@ $('#instance-preview').live('click', function(e) {
 
 $('#series-preview').live('click', function(e) {
   if ($.mobile.pageData) {
-    GetResource('/series/' + $.mobile.pageData.uuid, function(series) {
-      GetResource('/series/' + $.mobile.pageData.uuid + '/instances', function(instances) {
+    var pageData = DeepCopy($.mobile.pageData);
+
+    GetResource('/series/' + pageData.uuid, function(series) {
+      GetResource('/series/' + pageData.uuid + '/instances', function(instances) {
         Sort(instances, function(x) { return x.IndexInSeries; }, true, false);
 
         var images = [];
@@ -858,6 +900,8 @@ function ChooseDicomModality(callback)
 
 $('#instance-store,#series-store,#study-store,#patient-store').live('click', function(e) {
   ChooseDicomModality(function(modality, peer) {
+    var pageData = DeepCopy($.mobile.pageData);
+
     var url;
     var loading;
 
@@ -878,7 +922,7 @@ $('#instance-store,#series-store,#study-store,#patient-store').live('click', fun
         url: url,
         type: 'POST',
         dataType: 'text',
-        data: $.mobile.pageData.uuid,
+        data: pageData.uuid,
         async: true,  // Necessary to block UI
         beforeSend: function() {
           $.blockUI({ message: $(loading) });
diff --git a/OrthancExplorer/file-upload.js b/OrthancExplorer/file-upload.js
index 4749335..72f794e 100644
--- a/OrthancExplorer/file-upload.js
+++ b/OrthancExplorer/file-upload.js
@@ -48,6 +48,11 @@ $(document).ready(function() {
 
 
 $('#upload').live('pageshow', function() {
+  alert('WARNING - This page is currently affected by Orthanc issue #21: ' +
+        '"DICOM files might be missing after uploading with Mozilla Firefox." ' +
+        'Do not use this upload feature for clinical uses, or carefully ' +
+        'check that all instances have been properly received by Orthanc. ' +
+        'Please use the command-line "ImportDicomFiles.py" script to circumvent this issue.');
   $('#fileupload').fileupload('enable');
 });
 
diff --git a/OrthancExplorer/query-retrieve.js b/OrthancExplorer/query-retrieve.js
index 14f713f..1e4d4ae 100644
--- a/OrthancExplorer/query-retrieve.js
+++ b/OrthancExplorer/query-retrieve.js
@@ -1,294 +1,322 @@
-function JavascriptDateToDicom(date)
-{
-  var s = date.toISOString();
-  return s.substring(0, 4) + s.substring(5, 7) + s.substring(8, 10);
-}
-
-function GenerateDicomDate(days)
-{
-  var today = new Date();
-  var other = new Date(today);
-  other.setDate(today.getDate() + days);
-  return JavascriptDateToDicom(other);
-}
-
-
-$('#query-retrieve').live('pagebeforeshow', function() {
-  $.ajax({
-    url: '../modalities',
-    dataType: 'json',
-    async: false,
-    cache: false,
-    success: function(modalities) {
-      var target = $('#qr-server');
-      $('option', target).remove();
-
-      for (var i = 0; i < modalities.length; i++) {
-        var option = $('<option>').text(modalities[i]);
-        target.append(option);
-      }
-
-      target.selectmenu('refresh');
-    }
-  });
-
-  var target = $('#qr-date');
-  $('option', target).remove();
-  target.append($('<option>').attr('value', '*').text('Any date'));
-  target.append($('<option>').attr('value', GenerateDicomDate(0)).text('Today'));
-  target.append($('<option>').attr('value', GenerateDicomDate(-1)).text('Yesterday'));
-  target.append($('<option>').attr('value', GenerateDicomDate(-7) + '-').text('Last 7 days'));
-  target.append($('<option>').attr('value', GenerateDicomDate(-31) + '-').text('Last 31 days'));
-  target.append($('<option>').attr('value', GenerateDicomDate(-31 * 3) + '-').text('Last 3 months'));
-  target.append($('<option>').attr('value', GenerateDicomDate(-365) + '-').text('Last year'));
-  target.selectmenu('refresh');
-});
-
-
-$('#qr-echo').live('click', function() {
-  var server = $('#qr-server').val();
-  var message = 'Error: The C-Echo has failed!';
-
-  $.ajax({
-    url: '../modalities/' + server + '/echo',
-    type: 'POST', 
-    cache: false,
-    async: false,
-    success: function() {
-      message = 'The C-Echo has succeeded!';
-    }
-  });
-
-  $('<div>').simpledialog2({
-    mode: 'button',
-    headerText: 'Echo result',
-    headerClose: true,
-    buttonPrompt: message,
-    animate: false,
-    buttons : {
-      'OK': { click: function () { } }
-    }
-  });
-
-  return false;
-});
-
-
-$('#qr-submit').live('click', function() {
-  var query = {
-    'Level' : 'Study',
-    'Query' : {
-      'AccessionNumber' : '*',
-      'PatientBirthDate' : '*',
-      'PatientID' : '*',
-      'PatientName' : '*',
-      'PatientSex' : '*',
-      'SpecificCharacterSet' : 'ISO_IR 192',  // UTF-8
-      'StudyDate' : $('#qr-date').val(),
-      'StudyDescription' : '*'
-    }
-  };
-
-  var field = $('#qr-fields input:checked').val();
-  query['Query'][field] = $('#qr-value').val().toUpperCase();
-
-  var modalities = '';
-  $('#qr-modalities input:checked').each(function() {
-    var s = $(this).attr('name');
-    if (modalities == '*')
-      modalities = s;
-    else
-      modalities += '\\' + s;
-  });
-
-  if (modalities.length > 0) {
-    query['Query']['ModalitiesInStudy'] = modalities;
-  }
-
-
-  var server = $('#qr-server').val();
-  $.ajax({
-    url: '../modalities/' + server + '/query',
-    type: 'POST', 
-    data: JSON.stringify(query),
-    dataType: 'json',
-    async: false,
-    error: function() {
-      alert('Error during query (C-Find)');
-    },
-    success: function(result) {
-      window.location.assign('explorer.html#query-retrieve-2?server=' + server + '&uuid=' + result['ID']);
-    }
-  });
-
-  return false;
-});
-
-
-
-function Retrieve(url)
-{
-  $.ajax({
-    url: '../system',
-    dataType: 'json',
-    async: false,
-    success: function(system) {
-      $('<div>').simpledialog2({
-        mode: 'button',
-        headerText: 'Target',
-        headerClose: true,
-        buttonPrompt: 'Enter Application Entity Title (AET):',
-        buttonInput: true,
-        buttonInputDefault: system['DicomAet'],
-        buttons : {
-          'OK': {
-            click: function () { 
-              var aet = $.mobile.sdLastInput;
-              if (aet.length == 0)
-                aet = system['DicomAet'];
-
-              $.ajax({
-                url: url,
-                type: 'POST',
-                async: true,  // Necessary to block UI
-                dataType: 'text',
-                data: aet,
-                beforeSend: function() {
-                  $.blockUI({ message: $('#info-retrieve') });
-                },
-                complete: function(s) {
-                  $.unblockUI();
-                },
-                error: function() {
-                  alert('Error during retrieve');
-                }
-              });
-            }
-          }
-        }
-      });
-    }
-  });
-}
-
-
-
-
-$('#query-retrieve-2').live('pagebeforeshow', function() {
-  if ($.mobile.pageData) {
-    var uri = '../queries/' + $.mobile.pageData.uuid + '/answers';
-
-    $.ajax({
-      url: uri,
-      dataType: 'json',
-      async: false,
-      success: function(answers) {
-        var target = $('#query-retrieve-2 ul');
-        $('li', target).remove();
-
-        for (var i = 0; i < answers.length; i++) {
-          $.ajax({
-            url: uri + '/' + answers[i] + '/content?simplify',
-            dataType: 'json',
-            async: false,
-            success: function(study) {
-              var series = '#query-retrieve-3?server=' + $.mobile.pageData.server + '&uuid=' + study['StudyInstanceUID'];
-              var info = $('<a>').attr('href', series).html(
-                ('<h3>{0} - {1}</h3>' + 
-                 '<p>Accession number: <b>{2}</b></p>' +
-                 '<p>Birth date: <b>{3}</b></p>' +
-                 '<p>Patient sex: <b>{4}</b></p>' +
-                 '<p>Study description: <b>{5}</b></p>' +
-                 '<p>Study date: <b>{6}</b></p>').format(
-                   study['PatientID'],
-                   study['PatientName'],
-                   study['AccessionNumber'],
-                   FormatDicomDate(study['PatientBirthDate']),
-                   study['PatientSex'],
-                   study['StudyDescription'],
-                   FormatDicomDate(study['StudyDate'])));
-
-              var studyUri = uri + '/' + answers[i] + '/retrieve';
-              var retrieve = $('<a>').text('Retrieve').click(function() {
-                Retrieve(studyUri);
-              });
-
-              target.append($('<li>').append(info).append(retrieve));
-            }
-          });
-        }
-
-        target.listview('refresh');
-      }
-    });
-  }
-});
-
-
-$('#query-retrieve-3').live('pagebeforeshow', function() {
-  if ($.mobile.pageData) {
-    var query = {
-      'Level' : 'Series',
-      'Query' : {
-        'Modality' : '*',
-        'ProtocolName' : '*',
-        'SeriesDescription' : '*',
-        'SeriesInstanceUID' : '*',
-        'StudyInstanceUID' : $.mobile.pageData.uuid
-      }
-    };
-
-    $.ajax({
-      url: '../modalities/' + $.mobile.pageData.server + '/query',
-      type: 'POST', 
-      data: JSON.stringify(query),
-      dataType: 'json',
-      async: false,
-      error: function() {
-        alert('Error during query (C-Find)');
-      },
-      success: function(answer) {
-        var uri = '../queries/' + answer['ID'] + '/answers';
-
-        $.ajax({
-          url: uri,
-          dataType: 'json',
-          async: false,
-          success: function(answers) {
-            
-            var target = $('#query-retrieve-3 ul');
-            $('li', target).remove();
-
-            for (var i = 0; i < answers.length; i++) {
-              $.ajax({
-                url: uri + '/' + answers[i] + '/content?simplify',
-                dataType: 'json',
-                async: false,
-                success: function(series) {
-                  var info = $('<a>').html(
-                    ('<h3>{0}</h3>'  + 
-                     '<p>Modality: <b>{1}</b></p>' +
-                     '<p>Protocol name: <b>{2}</b></p>'
-                    ).format(
-                      series['SeriesDescription'],
-                      series['Modality'],
-                      series['ProtocolName']
-                    ));
-
-                  var seriesUri = uri + '/' + answers[i] + '/retrieve';
-                  var retrieve = $('<a>').text('Retrieve').click(function() {
-                    Retrieve(seriesUri);
-                  });
-
-                  target.append($('<li>').append(info).append(retrieve));
-                }
-              });
-            }
-
-            target.listview('refresh');
-          }
-        });
-      }
-    });
-  }
-});
+function JavascriptDateToDicom(date)
+{
+  var s = date.toISOString();
+  return s.substring(0, 4) + s.substring(5, 7) + s.substring(8, 10);
+}
+
+function GenerateDicomDate(days)
+{
+  var today = new Date();
+  var other = new Date(today);
+  other.setDate(today.getDate() + days);
+  return JavascriptDateToDicom(other);
+}
+
+
+$('#query-retrieve').live('pagebeforeshow', function() {
+  $.ajax({
+    url: '../modalities',
+    dataType: 'json',
+    async: false,
+    cache: false,
+    success: function(modalities) {
+      var target = $('#qr-server');
+      $('option', target).remove();
+
+      for (var i = 0; i < modalities.length; i++) {
+        var option = $('<option>').text(modalities[i]);
+        target.append(option);
+      }
+
+      target.selectmenu('refresh');
+    }
+  });
+
+  var target = $('#qr-date');
+  $('option', target).remove();
+  target.append($('<option>').attr('value', '*').text('Any date'));
+  target.append($('<option>').attr('value', GenerateDicomDate(0)).text('Today'));
+  target.append($('<option>').attr('value', GenerateDicomDate(-1)).text('Yesterday'));
+  target.append($('<option>').attr('value', GenerateDicomDate(-7) + '-').text('Last 7 days'));
+  target.append($('<option>').attr('value', GenerateDicomDate(-31) + '-').text('Last 31 days'));
+  target.append($('<option>').attr('value', GenerateDicomDate(-31 * 3) + '-').text('Last 3 months'));
+  target.append($('<option>').attr('value', GenerateDicomDate(-365) + '-').text('Last year'));
+  target.selectmenu('refresh');
+});
+
+
+$('#qr-echo').live('click', function() {
+  var server = $('#qr-server').val();
+  var message = 'Error: The C-Echo has failed!';
+
+  $.ajax({
+    url: '../modalities/' + server + '/echo',
+    type: 'POST', 
+    cache: false,
+    async: false,
+    success: function() {
+      message = 'The C-Echo has succeeded!';
+    }
+  });
+
+  $('<div>').simpledialog2({
+    mode: 'button',
+    headerText: 'Echo result',
+    headerClose: true,
+    buttonPrompt: message,
+    animate: false,
+    buttons : {
+      'OK': { click: function () { } }
+    }
+  });
+
+  return false;
+});
+
+
+$('#qr-submit').live('click', function() {
+  var query = {
+    'Level' : 'Study',
+    'Query' : {
+      'AccessionNumber' : '*',
+      'PatientBirthDate' : '*',
+      'PatientID' : '*',
+      'PatientName' : '*',
+      'PatientSex' : '*',
+      'StudyDate' : $('#qr-date').val(),
+      'StudyDescription' : '*'
+    }
+  };
+
+  var field = $('#qr-fields input:checked').val();
+  query['Query'][field] = $('#qr-value').val().toUpperCase();
+
+  var modalities = '';
+  $('#qr-modalities input:checked').each(function() {
+    var s = $(this).attr('name');
+    if (modalities == '')
+      modalities = s;
+    else
+      modalities += '\\' + s;
+  });
+
+  if (modalities.length > 0) {
+    query['Query']['ModalitiesInStudy'] = modalities;
+  }
+
+
+  var server = $('#qr-server').val();
+  $.ajax({
+    url: '../modalities/' + server + '/query',
+    type: 'POST', 
+    data: JSON.stringify(query),
+    dataType: 'json',
+    async: false,
+    error: function() {
+      alert('Error during query (C-Find)');
+    },
+    success: function(result) {
+      ChangePage('query-retrieve-2', {
+        'server' : server,
+        'uuid' : result['ID']
+      });
+    }
+  });
+
+  return false;
+});
+
+
+
+$('#query-retrieve-2').live('pagebeforeshow', function() {
+  if ($.mobile.pageData) {
+    var pageData = DeepCopy($.mobile.pageData);
+
+    var uri = '../queries/' + pageData.uuid + '/answers';
+
+    $.ajax({
+      url: uri,
+      dataType: 'json',
+      async: false,
+      success: function(answers) {
+        var target = $('#query-retrieve-2 ul');
+        $('li', target).remove();
+
+        for (var i = 0; i < answers.length; i++) {
+          $.ajax({
+            url: uri + '/' + answers[i] + '/content?simplify',
+            dataType: 'json',
+            async: false,
+            success: function(study) {
+              var series = '#query-retrieve-3?server=' + pageData.server + '&uuid=' + study['StudyInstanceUID'];
+              var info = $('<a>').attr('href', series).html(
+                ('<h3>{0} - {1}</h3>' + 
+                 '<p>Accession number: <b>{2}</b></p>' +
+                 '<p>Birth date: <b>{3}</b></p>' +
+                 '<p>Patient sex: <b>{4}</b></p>' +
+                 '<p>Study description: <b>{5}</b></p>' +
+                 '<p>Study date: <b>{6}</b></p>').format(
+                   study['PatientID'],
+                   study['PatientName'],
+                   study['AccessionNumber'],
+                   FormatDicomDate(study['PatientBirthDate']),
+                   study['PatientSex'],
+                   study['StudyDescription'],
+                   FormatDicomDate(study['StudyDate'])));
+
+              var answerId = answers[i];
+              var retrieve = $('<a>').text('Retrieve all study').click(function() {
+                ChangePage('query-retrieve-4', {
+                  'query' : pageData.uuid,
+                  'answer' : answerId,
+                  'server' : pageData.server
+                });
+              });
+
+              target.append($('<li>').append(info).append(retrieve));
+            }
+          });
+        }
+
+        target.listview('refresh');
+      }
+    });
+  }
+});
+
+
+$('#query-retrieve-3').live('pagebeforeshow', function() {
+  if ($.mobile.pageData) {
+    var pageData = DeepCopy($.mobile.pageData);
+
+    var query = {
+      'Level' : 'Series',
+      'Query' : {
+        'Modality' : '*',
+        'ProtocolName' : '*',
+        'SeriesDescription' : '*',
+        'SeriesInstanceUID' : '*',
+        'StudyInstanceUID' : pageData.uuid
+      }
+    };
+
+    $.ajax({
+      url: '../modalities/' + pageData.server + '/query',
+      type: 'POST', 
+      data: JSON.stringify(query),
+      dataType: 'json',
+      async: false,
+      error: function() {
+        alert('Error during query (C-Find)');
+      },
+      success: function(answer) {
+        var queryUuid = answer['ID'];
+        var uri = '../queries/' + answer['ID'] + '/answers';
+
+        $.ajax({
+          url: uri,
+          dataType: 'json',
+          async: false,
+          success: function(answers) {
+            
+            var target = $('#query-retrieve-3 ul');
+            $('li', target).remove();
+
+            for (var i = 0; i < answers.length; i++) {
+              $.ajax({
+                url: uri + '/' + answers[i] + '/content?simplify',
+                dataType: 'json',
+                async: false,
+                success: function(series) {
+                  var info = $('<a>').html(
+                    ('<h3>{0}</h3>'  + 
+                     '<p>Modality: <b>{1}</b></p>' +
+                     '<p>Protocol name: <b>{2}</b></p>'
+                    ).format(
+                      series['SeriesDescription'],
+                      series['Modality'],
+                      series['ProtocolName']
+                    ));
+
+                  var answerId = answers[i];
+                  info.click(function() {
+                    ChangePage('query-retrieve-4', {
+                      'query' : queryUuid,
+                      'study' : pageData.uuid,
+                      'answer' : answerId,
+                      'server' : pageData.server
+                    });
+                  });
+
+                  target.append($('<li>').attr('data-icon', 'arrow-d').append(info));
+                }
+              });
+            }
+
+            target.listview('refresh');
+          }
+        });
+      }
+    });
+  }
+});
+
+
+
+$('#query-retrieve-4').live('pagebeforeshow', function() {
+  if ($.mobile.pageData) {
+    var pageData = DeepCopy($.mobile.pageData);
+    var uri = '../queries/' + pageData.query + '/answers/' + pageData.answer + '/retrieve';
+
+    $.ajax({
+      url: '../system',
+      dataType: 'json',
+      async: false,
+      cache: false,
+      success: function(system) {
+        $('#retrieve-target').val(system['DicomAet']);
+
+        $('#retrieve-form').submit(function(event) {
+          event.preventDefault();
+
+          var aet = $('#retrieve-target').val();
+          if (aet.length == 0) {
+            aet = system['DicomAet'];
+          }
+
+          $.ajax({
+            url: uri,
+            type: 'POST',
+            async: true,  // Necessary to block UI
+            dataType: 'text',
+            data: aet,
+            beforeSend: function() {
+              $.blockUI({ message: $('#info-retrieve') });
+            },
+            complete: function(s) {
+              $.unblockUI();
+            },
+            success: function() {
+              if (pageData.study) {
+                // Go back to the list of series
+                ChangePage('query-retrieve-3', {
+                  'server' : pageData.server,
+                  'uuid' : pageData.study
+                });
+              } else {
+                // Go back to the list of studies
+                ChangePage('query-retrieve-2', {
+                  'server' : pageData.server,
+                  'uuid' : pageData.query
+                });
+              }
+            },
+            error: function() {
+              alert('Error during retrieve');
+            }
+          });
+        });
+      }
+    });
+  }
+});
diff --git a/OrthancServer/DatabaseWrapper.cpp b/OrthancServer/DatabaseWrapper.cpp
index 4433255..032509a 100644
--- a/OrthancServer/DatabaseWrapper.cpp
+++ b/OrthancServer/DatabaseWrapper.cpp
@@ -35,7 +35,6 @@
 
 #include "../Core/DicomFormat/DicomArray.h"
 #include "../Core/Logging.h"
-#include "../Core/Uuid.h"
 #include "EmbeddedResources.h"
 #include "ServerToolbox.h"
 
@@ -373,10 +372,10 @@ namespace Orthanc
       // consists in reconstructing the main DICOM tags information
       // (as more tags got included).
       db_.BeginTransaction();
-      Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Patient);
-      Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Study);
-      Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Series);
-      Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Instance);
+      ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Patient);
+      ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Study);
+      ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Series);
+      ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Instance);
       db_.Execute("UPDATE GlobalProperties SET value=\"6\" WHERE property=" +
                   boost::lexical_cast<std::string>(GlobalProperty_DatabaseSchemaVersion) + ";");
       db_.CommitTransaction();
diff --git a/OrthancServer/DicomDirWriter.cpp b/OrthancServer/DicomDirWriter.cpp
index 6f77011..fbe998f 100644
--- a/OrthancServer/DicomDirWriter.cpp
+++ b/OrthancServer/DicomDirWriter.cpp
@@ -105,7 +105,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "../Core/Logging.h"
 #include "../Core/OrthancException.h"
-#include "../Core/Uuid.h"
+#include "../Core/TemporaryFile.h"
+#include "../Core/Toolbox.h"
+#include "../Core/SystemToolbox.h"
 
 #include <dcmtk/dcmdata/dcdicdir.h>
 #include <dcmtk/dcmdata/dcmetinf.h>
@@ -126,7 +128,7 @@ namespace Orthanc
   {
   private:
     std::string fileSetId_;
-    Toolbox::TemporaryFile file_;
+    TemporaryFile file_;
     std::auto_ptr<DcmDicomDir> dir_;
 
     typedef std::pair<ResourceType, std::string>  IndexKey;
@@ -260,7 +262,7 @@ namespace Orthanc
       // cf. "DicomDirInterface::buildStudyRecord()"
 
       std::string nowDate, nowTime;
-      Toolbox::GetNowDicom(nowDate, nowTime);
+      SystemToolbox::GetNowDicom(nowDate, nowTime);
 
       std::string studyDate;
       if (!GetUtf8TagValue(studyDate, dicom, encoding, DCM_StudyDate) &&
diff --git a/OrthancServer/DicomInstanceToStore.cpp b/OrthancServer/DicomInstanceToStore.cpp
index 2f0717c..3851187 100644
--- a/OrthancServer/DicomInstanceToStore.cpp
+++ b/OrthancServer/DicomInstanceToStore.cpp
@@ -38,6 +38,7 @@
 #include "../Core/Logging.h"
 
 #include <dcmtk/dcmdata/dcfilefo.h>
+#include <dcmtk/dcmdata/dcdeftag.h>
 
 
 namespace Orthanc
@@ -104,21 +105,15 @@ namespace Orthanc
     if (!summary_.HasContent())
     {
       summary_.Allocate();
-      FromDcmtkBridge::Convert(summary_.GetContent(), 
-                               *parsed_.GetContent().GetDcmtkObject().getDataset(),
-                               ORTHANC_MAXIMUM_TAG_LENGTH,                               
-                               Configuration::GetDefaultEncoding());
+      Configuration::ExtractDicomSummary(summary_.GetContent(), 
+                                         *parsed_.GetContent().GetDcmtkObject().getDataset());
     }
     
     if (!json_.HasContent())
     {
       json_.Allocate();
-      FromDcmtkBridge::ToJson(json_.GetContent(), 
-                              *parsed_.GetContent().GetDcmtkObject().getDataset(),
-                              DicomToJsonFormat_Full, 
-                              DicomToJsonFlags_Default,
-                              ORTHANC_MAXIMUM_TAG_LENGTH,
-                              Configuration::GetDefaultEncoding());
+      Configuration::ExtractDicomAsJson(json_.GetContent(), 
+                                        *parsed_.GetContent().GetDcmtkObject().getDataset());
     }
   }
 
@@ -276,4 +271,25 @@ namespace Orthanc
       return "";
     }
   }
+
+
+  bool DicomInstanceToStore::LookupTransferSyntax(std::string& result)
+  {
+    ComputeMissingInformation();
+
+    DicomMap header;
+    if (DicomMap::ParseDicomMetaInformation(header, GetBufferData(), GetBufferSize()))
+    {
+      const DicomValue* value = header.TestAndGetValue(DICOM_TAG_TRANSFER_SYNTAX_UID);
+      if (value != NULL &&
+          !value->IsBinary() &&
+          !value->IsNull())
+      {
+        result = Toolbox::StripSpaces(value->GetContent());
+        return true;
+      }
+    }
+
+    return false;
+  }
 }
diff --git a/OrthancServer/DicomInstanceToStore.h b/OrthancServer/DicomInstanceToStore.h
index 5d7f318..7723922 100644
--- a/OrthancServer/DicomInstanceToStore.h
+++ b/OrthancServer/DicomInstanceToStore.h
@@ -221,5 +221,7 @@ namespace Orthanc
     const Json::Value& GetJson();
 
     void GetOriginInformation(Json::Value& result) const;
+
+    bool LookupTransferSyntax(std::string& result);
   };
 }
diff --git a/OrthancServer/DicomModification.cpp b/OrthancServer/DicomModification.cpp
index 896300b..35a0afd 100644
--- a/OrthancServer/DicomModification.cpp
+++ b/OrthancServer/DicomModification.cpp
@@ -144,11 +144,13 @@ namespace Orthanc
     dicom.Replace(*tag, mapped, false /* don't try and decode data URI scheme for UIDs */, DicomReplaceMode_InsertIfAbsent);
   }
   
-  DicomModification::DicomModification()
+  DicomModification::DicomModification() :
+    removePrivateTags_(false),
+    level_(ResourceType_Instance),
+    allowManualIdentifiers_(true),
+    keepStudyInstanceUid_(false),
+    keepSeriesInstanceUid_(false)
   {
-    removePrivateTags_ = false;
-    level_ = ResourceType_Instance;
-    allowManualIdentifiers_ = true;
   }
 
   DicomModification::~DicomModification()
@@ -166,6 +168,16 @@ namespace Orthanc
       privateTagsToKeep_.insert(tag);
     }
 
+    if (tag == DICOM_TAG_STUDY_INSTANCE_UID)
+    {
+      keepStudyInstanceUid_ = true;
+    }
+
+    if (tag == DICOM_TAG_SERIES_INSTANCE_UID)
+    {
+      keepSeriesInstanceUid_ = true;
+    }
+
     MarkNotOrthancAnonymization();
   }
 
@@ -466,13 +478,27 @@ namespace Orthanc
     if (level_ <= ResourceType_Study &&
         !IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
     {
-      MapDicomIdentifier(toModify, ResourceType_Study);
+      if (keepStudyInstanceUid_)
+      {
+        LOG(WARNING) << "Modifying a study while keeping its original StudyInstanceUID: This should be avoided!";
+      }
+      else
+      {
+        MapDicomIdentifier(toModify, ResourceType_Study);
+      }
     }
 
     if (level_ <= ResourceType_Series &&
         !IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
     {
-      MapDicomIdentifier(toModify, ResourceType_Series);
+      if (keepSeriesInstanceUid_)
+      {
+        LOG(WARNING) << "Modifying a series while keeping its original SeriesInstanceUID: This should be avoided!";
+      }
+      else
+      {
+        MapDicomIdentifier(toModify, ResourceType_Series);
+      }
     }
 
     if (level_ <= ResourceType_Instance &&  // Always true
diff --git a/OrthancServer/DicomModification.h b/OrthancServer/DicomModification.h
index 5e10de4..e92c177 100644
--- a/OrthancServer/DicomModification.h
+++ b/OrthancServer/DicomModification.h
@@ -57,6 +57,8 @@ namespace Orthanc
     UidMap uidMap_;
     SetOfTags privateTagsToKeep_;
     bool allowManualIdentifiers_;
+    bool keepStudyInstanceUid_;
+    bool keepSeriesInstanceUid_;
 
     void MapDicomIdentifier(ParsedDicomFile& dicom,
                             ResourceType level);
diff --git a/OrthancServer/DicomProtocol/DicomFindAnswers.cpp b/OrthancServer/DicomProtocol/DicomFindAnswers.cpp
index c649932..be15a63 100644
--- a/OrthancServer/DicomProtocol/DicomFindAnswers.cpp
+++ b/OrthancServer/DicomProtocol/DicomFindAnswers.cpp
@@ -33,8 +33,8 @@
 #include "../PrecompiledHeadersServer.h"
 #include "DicomFindAnswers.h"
 
+#include "../OrthancInitialization.h"
 #include "../FromDcmtkBridge.h"
-#include "../ToDcmtkBridge.h"
 #include "../../Core/OrthancException.h"
 
 #include <memory>
@@ -44,80 +44,56 @@
 
 namespace Orthanc
 {
-  class DicomFindAnswers::Answer : public boost::noncopyable
+  void DicomFindAnswers::AddAnswerInternal(ParsedDicomFile* answer)
   {
-  private:
-    ParsedDicomFile* dicom_;
-    DicomMap*        map_;
+    std::auto_ptr<ParsedDicomFile> protection(answer);
 
-    void CleanupDicom()
+    if (isWorklist_)
     {
-      if (dicom_ != NULL)
-      {
-        dicom_->Remove(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID);
-        dicom_->Remove(DICOM_TAG_SOP_INSTANCE_UID);
-      }
+      // These lines are necessary when serving worklists, otherwise
+      // Orthanc does not behave as "wlmscpfs"
+      protection->Remove(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID);
+      protection->Remove(DICOM_TAG_SOP_INSTANCE_UID);
     }
 
-  public:
-    Answer(ParsedDicomFile& dicom) : 
-      dicom_(dicom.Clone()),
-      map_(NULL)
-    {
-      CleanupDicom();
-    }
+    protection->ChangeEncoding(encoding_);
 
-    Answer(const void* dicom,
-           size_t size) : 
-      dicom_(new ParsedDicomFile(dicom, size)),
-      map_(NULL)
-    {
-      CleanupDicom();
-    }
+    answers_.push_back(protection.release());
+  }
 
-    Answer(const DicomMap& map) : 
-      dicom_(NULL),
-      map_(map.Clone())
-    {
-    }
 
-    ~Answer()
+  DicomFindAnswers::DicomFindAnswers(bool isWorklist) : 
+    encoding_(Configuration::GetDefaultEncoding()),
+    isWorklist_(isWorklist),
+    complete_(true)
+  {
+  }
+
+
+  void DicomFindAnswers::SetEncoding(Encoding encoding)
+  {
+    for (size_t i = 0; i < answers_.size(); i++)
     {
-      if (dicom_ != NULL)
-      {
-        delete dicom_;
-      }
-
-      if (map_ != NULL)
-      {
-        delete map_;
-      }
+      assert(answers_[i] != NULL);
+      answers_[i]->ChangeEncoding(encoding);
     }
 
-    ParsedDicomFile& GetDicomFile()
-    {
-      if (dicom_ == NULL)
-      {
-        assert(map_ != NULL);
-        dicom_ = new ParsedDicomFile(*map_);
-      }
+    encoding_ = encoding;
+  }
 
-      return *dicom_;
-    }
 
-    DcmDataset* ExtractDcmDataset() const
+  void DicomFindAnswers::SetWorklist(bool isWorklist)
+  {
+    if (answers_.empty())
     {
-      if (dicom_ != NULL)
-      {
-        return new DcmDataset(*dicom_->GetDcmtkObject().getDataset());
-      }
-      else
-      {
-        assert(map_ != NULL);
-        return ToDcmtkBridge::Convert(*map_);
-      }
+      isWorklist_ = isWorklist;
     }
-  };
+    else
+    {
+      // This set of answers is not empty anymore, cannot change its type
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+  }
 
 
   void DicomFindAnswers::Clear()
@@ -143,28 +119,27 @@ namespace Orthanc
 
   void DicomFindAnswers::Add(const DicomMap& map)
   {
-    answers_.push_back(new Answer(map));
+    AddAnswerInternal(new ParsedDicomFile(map, encoding_));
   }
 
 
   void DicomFindAnswers::Add(ParsedDicomFile& dicom)
   {
-    answers_.push_back(new Answer(dicom));
+    AddAnswerInternal(dicom.Clone());
   }
 
-
   void DicomFindAnswers::Add(const void* dicom,
                              size_t size)
   {
-    answers_.push_back(new Answer(dicom, size));
+    AddAnswerInternal(new ParsedDicomFile(dicom, size));
   }
 
 
-  DicomFindAnswers::Answer& DicomFindAnswers::GetAnswerInternal(size_t index) const
+  ParsedDicomFile& DicomFindAnswers::GetAnswer(size_t index) const
   {
     if (index < answers_.size())
     {
-      return *answers_.at(index);
+      return *answers_[index];
     }
     else
     {
@@ -173,15 +148,9 @@ namespace Orthanc
   }
 
 
-  ParsedDicomFile& DicomFindAnswers::GetAnswer(size_t index) const
-  {
-    return GetAnswerInternal(index).GetDicomFile();
-  }
-
-
   DcmDataset* DicomFindAnswers::ExtractDcmDataset(size_t index) const
   {
-    return GetAnswerInternal(index).ExtractDcmDataset();
+    return new DcmDataset(*GetAnswer(index).GetDcmtkObject().getDataset());
   }
 
 
@@ -190,7 +159,7 @@ namespace Orthanc
                                 bool simplify) const
   {
     DicomToJsonFormat format = (simplify ? DicomToJsonFormat_Human : DicomToJsonFormat_Full);
-    GetAnswer(index).ToJson(target, format, DicomToJsonFlags_None, 0);
+    GetAnswer(index).DatasetToJson(target, format, DicomToJsonFlags_None, 0);
   }
 
 
diff --git a/OrthancServer/DicomProtocol/DicomFindAnswers.h b/OrthancServer/DicomProtocol/DicomFindAnswers.h
index 5dfc23c..f06bbe9 100644
--- a/OrthancServer/DicomProtocol/DicomFindAnswers.h
+++ b/OrthancServer/DicomProtocol/DicomFindAnswers.h
@@ -39,23 +39,35 @@ namespace Orthanc
   class DicomFindAnswers : public boost::noncopyable
   {
   private:
-    class Answer;
+    Encoding                      encoding_;
+    bool                          isWorklist_;
+    std::vector<ParsedDicomFile*> answers_;
+    bool                          complete_;
 
-    std::vector<Answer*> answers_;
-    bool                 complete_;
-
-    Answer& GetAnswerInternal(size_t index) const;
+    void AddAnswerInternal(ParsedDicomFile* answer);
 
   public:
-    DicomFindAnswers() : complete_(true)
-    {
-    }
+    DicomFindAnswers(bool isWorklist);
 
     ~DicomFindAnswers()
     {
       Clear();
     }
 
+    Encoding GetEncoding() const
+    {
+      return encoding_;
+    }
+
+    void SetEncoding(Encoding encoding);
+
+    void SetWorklist(bool isWorklist);
+
+    bool IsWorklist() const
+    {
+      return isWorklist_;
+    }
+
     void Clear();
 
     void Reserve(size_t index);
diff --git a/OrthancServer/DicomProtocol/DicomServer.cpp b/OrthancServer/DicomProtocol/DicomServer.cpp
index deb80aa..b908420 100644
--- a/OrthancServer/DicomProtocol/DicomServer.cpp
+++ b/OrthancServer/DicomProtocol/DicomServer.cpp
@@ -36,7 +36,6 @@
 #include "../../Core/Logging.h"
 #include "../../Core/OrthancException.h"
 #include "../../Core/Toolbox.h"
-#include "../../Core/Uuid.h"
 #include "../Internals/CommandDispatcher.h"
 #include "../OrthancInitialization.h"
 #include "EmbeddedResources.h"
@@ -97,7 +96,7 @@ namespace Orthanc
     worklistRequestHandlerFactory_ = NULL;
     applicationEntityFilter_ = NULL;
     checkCalledAet_ = true;
-    clientTimeout_ = 30;
+    associationTimeout_ = 30;
     continue_ = false;
   }
 
@@ -121,15 +120,18 @@ namespace Orthanc
     return port_;
   }
 
-  void DicomServer::SetClientTimeout(uint32_t timeout)
+  void DicomServer::SetAssociationTimeout(uint32_t seconds)
   {
+    LOG(INFO) << "Setting timeout for DICOM connections if Orthanc acts as SCP (server): " 
+              << seconds << " seconds (0 = no timeout)";
+
     Stop();
-    clientTimeout_ = timeout;
+    associationTimeout_ = seconds;
   }
 
-  uint32_t DicomServer::GetClientTimeout() const
+  uint32_t DicomServer::GetAssociationTimeout() const
   {
-    return clientTimeout_;
+    return associationTimeout_;
   }
 
 
diff --git a/OrthancServer/DicomProtocol/DicomServer.h b/OrthancServer/DicomProtocol/DicomServer.h
index 807f13c..f4d5f3a 100644
--- a/OrthancServer/DicomProtocol/DicomServer.h
+++ b/OrthancServer/DicomProtocol/DicomServer.h
@@ -54,7 +54,7 @@ namespace Orthanc
     std::string aet_;
     uint16_t port_;
     bool continue_;
-    uint32_t clientTimeout_;
+    uint32_t associationTimeout_;
     IFindRequestHandlerFactory* findRequestHandlerFactory_;
     IMoveRequestHandlerFactory* moveRequestHandlerFactory_;
     IStoreRequestHandlerFactory* storeRequestHandlerFactory_;
@@ -71,8 +71,8 @@ namespace Orthanc
     void SetPortNumber(uint16_t port);
     uint16_t GetPortNumber() const;
 
-    void SetClientTimeout(uint32_t timeout);
-    uint32_t GetClientTimeout() const;
+    void SetAssociationTimeout(uint32_t seconds);
+    uint32_t GetAssociationTimeout() const;
 
     void SetCalledApplicationEntityTitleCheck(bool check);
     bool HasCalledApplicationEntityTitleCheck() const;
diff --git a/OrthancServer/DicomProtocol/DicomUserConnection.cpp b/OrthancServer/DicomProtocol/DicomUserConnection.cpp
index 2636536..c8a7ff5 100644
--- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp
+++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp
@@ -133,6 +133,9 @@ static const unsigned int MAXIMUM_STORAGE_SOP_CLASSES = 64;
 
 namespace Orthanc
 {
+  // By default, the timeout for DICOM SCU (client) connections is set to 10 seconds
+  static uint32_t defaultTimeout_ = 10;
+
   struct DicomUserConnection::PImpl
   {
     // Connection state
@@ -151,6 +154,7 @@ namespace Orthanc
 
     void Store(DcmInputStream& is, 
                DicomUserConnection& connection,
+               const std::string& moveOriginatorAET,
                uint16_t moveOriginatorID);
   };
 
@@ -256,6 +260,7 @@ namespace Orthanc
 
   void DicomUserConnection::PImpl::Store(DcmInputStream& is, 
                                          DicomUserConnection& connection,
+                                         const std::string& moveOriginatorAET,
                                          uint16_t moveOriginatorID)
   {
     CheckIsOpen();
@@ -277,21 +282,21 @@ namespace Orthanc
     const std::string syntax(xfer.getXferID());
     bool isGeneric = IsGenericTransferSyntax(syntax);
 
-    bool renegociate;
+    bool renegotiate;
     if (isGeneric)
     {
       // Are we making a generic-to-specific or specific-to-generic change of
       // the transfer syntax? If this is the case, renegotiate the connection.
-      renegociate = !IsGenericTransferSyntax(connection.GetPreferredTransferSyntax());
+      renegotiate = !IsGenericTransferSyntax(connection.GetPreferredTransferSyntax());
     }
     else
     {
-      // We are using a specific transfer syntax. Renegociate if the
+      // We are using a specific transfer syntax. Renegotiate if the
       // current connection does not match this transfer syntax.
-      renegociate = (syntax != connection.GetPreferredTransferSyntax());
+      renegotiate = (syntax != connection.GetPreferredTransferSyntax());
     }
 
-    if (renegociate)
+    if (renegotiate)
     {
       LOG(INFO) << "Change in the transfer syntax: the C-Store associated must be renegotiated";
 
@@ -338,12 +343,12 @@ namespace Orthanc
     request.DataSetType = DIMSE_DATASET_PRESENT;
     strncpy(request.AffectedSOPInstanceUID, sopInstance, DIC_UI_LEN);
 
-    strncpy(request.MoveOriginatorApplicationEntityTitle, 
-            connection.GetLocalApplicationEntityTitle().c_str(), DIC_AE_LEN);
-    request.opts = O_STORE_MOVEORIGINATORAETITLE;
-
-    if (moveOriginatorID != 0)
+    if (!moveOriginatorAET.empty())
     {
+      strncpy(request.MoveOriginatorApplicationEntityTitle, 
+              moveOriginatorAET.c_str(), DIC_AE_LEN);
+      request.opts = O_STORE_MOVEORIGINATORAETITLE;
+
       request.MoveOriginatorID = moveOriginatorID;  // The type DIC_US is an alias for uint16_t
       request.opts |= O_STORE_MOVEORIGINATORID;
     }
@@ -395,9 +400,7 @@ namespace Orthanc
       else
       {
         DicomMap m;
-        FromDcmtkBridge::Convert(m, *responseIdentifiers, 
-                                 ORTHANC_MAXIMUM_TAG_LENGTH,
-                                 Configuration::GetDefaultEncoding());
+        Configuration::ExtractDicomSummary(m, *responseIdentifiers);
 
         if (!m.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL))
         {
@@ -477,8 +480,8 @@ namespace Orthanc
   }
 
 
-  static DcmDataset* ConvertQueryFields(const DicomMap& fields,
-                                        ModalityManufacturer manufacturer)
+  static ParsedDicomFile* ConvertQueryFields(const DicomMap& fields,
+                                             ModalityManufacturer manufacturer)
   {
     switch (manufacturer)
     {
@@ -512,11 +515,11 @@ namespace Orthanc
           }
         }
 
-        return ToDcmtkBridge::Convert(*fix);
+        return new ParsedDicomFile(*fix);
       }
 
       default:
-        return ToDcmtkBridge::Convert(fields);
+        return new ParsedDicomFile(fields);
     }
   }
 
@@ -576,7 +579,9 @@ namespace Orthanc
 
     CheckIsOpen();
 
-    std::auto_ptr<DcmDataset> dataset(ConvertQueryFields(fields, manufacturer_));
+    std::auto_ptr<ParsedDicomFile> query(ConvertQueryFields(fields, manufacturer_));
+    DcmDataset* dataset = query->GetDcmtkObject().getDataset();
+
     const char* clevel = NULL;
     const char* sopClass = NULL;
 
@@ -584,19 +589,19 @@ namespace Orthanc
     {
       case ResourceType_Patient:
         clevel = "PATIENT";
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "PATIENT");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "PATIENT");
         sopClass = UID_FINDPatientRootQueryRetrieveInformationModel;
         break;
 
       case ResourceType_Study:
         clevel = "STUDY";
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "STUDY");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "STUDY");
         sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
         break;
 
       case ResourceType_Series:
         clevel = "SERIES";
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "SERIES");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "SERIES");
         sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
         break;
 
@@ -608,11 +613,11 @@ namespace Orthanc
           // This is a particular case for ClearCanvas, thanks to Peter Somlo <peter.somlo at gmail.com>.
           // https://groups.google.com/d/msg/orthanc-users/j-6C3MAVwiw/iolB9hclom8J
           // http://www.clearcanvas.ca/Home/Community/OldForums/tabid/526/aff/11/aft/14670/afv/topic/Default.aspx
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "IMAGE");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "IMAGE");
         }
         else
         {
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "INSTANCE");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "INSTANCE");
         }
 
         sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
@@ -629,26 +634,26 @@ namespace Orthanc
       case ResourceType_Instance:
         // SOP Instance UID
         if (!fields.HasTag(0x0008, 0x0018))
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0018), "");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0018), "");
 
       case ResourceType_Series:
         // Series instance UID
         if (!fields.HasTag(0x0020, 0x000e))
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0020, 0x000e), "");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0020, 0x000e), "");
 
       case ResourceType_Study:
         // Accession number
         if (!fields.HasTag(0x0008, 0x0050))
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0050), "");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0050), "");
 
         // Study instance UID
         if (!fields.HasTag(0x0020, 0x000d))
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0020, 0x000d), "");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0020, 0x000d), "");
 
       case ResourceType_Patient:
         // Patient ID
         if (!fields.HasTag(0x0010, 0x0020))
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0010, 0x0020), "");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0010, 0x0020), "");
 
         break;
 
@@ -657,7 +662,7 @@ namespace Orthanc
     }
 
     assert(clevel != NULL && sopClass != NULL);
-    ExecuteFind(result, pimpl_->assoc_, dataset.get(), sopClass, false, clevel, pimpl_->dimseTimeout_);
+    ExecuteFind(result, pimpl_->assoc_, dataset, sopClass, false, clevel, pimpl_->dimseTimeout_);
   }
 
 
@@ -667,21 +672,22 @@ namespace Orthanc
   {
     CheckIsOpen();
 
-    std::auto_ptr<DcmDataset> dataset(ConvertQueryFields(fields, manufacturer_));
+    std::auto_ptr<ParsedDicomFile> query(ConvertQueryFields(fields, manufacturer_));
+    DcmDataset* dataset = query->GetDcmtkObject().getDataset();
 
     const char* sopClass = UID_MOVEStudyRootQueryRetrieveInformationModel;
     switch (level)
     {
       case ResourceType_Patient:
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "PATIENT");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "PATIENT");
         break;
 
       case ResourceType_Study:
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "STUDY");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "STUDY");
         break;
 
       case ResourceType_Series:
-        DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "SERIES");
+        DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "SERIES");
         break;
 
       case ResourceType_Instance:
@@ -691,11 +697,11 @@ namespace Orthanc
           // This is a particular case for ClearCanvas, thanks to Peter Somlo <peter.somlo at gmail.com>.
           // https://groups.google.com/d/msg/orthanc-users/j-6C3MAVwiw/iolB9hclom8J
           // http://www.clearcanvas.ca/Home/Community/OldForums/tabid/526/aff/11/aft/14670/afv/topic/Default.aspx
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "IMAGE");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "IMAGE");
         }
         else
         {
-          DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "INSTANCE");
+          DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "INSTANCE");
         }
         break;
 
@@ -721,7 +727,7 @@ namespace Orthanc
     T_DIMSE_C_MoveRSP response;
     DcmDataset* statusDetail = NULL;
     DcmDataset* responseIdentifiers = NULL;
-    OFCondition cond = DIMSE_moveUser(pimpl_->assoc_, presID, &request, dataset.get(),
+    OFCondition cond = DIMSE_moveUser(pimpl_->assoc_, presID, &request, dataset,
                                       NULL, NULL,
                                       /*opt_blockMode*/ DIMSE_BLOCKING, 
                                       /*opt_dimse_timeout*/ pimpl_->dimseTimeout_,
@@ -782,7 +788,7 @@ namespace Orthanc
     remotePort_ = 104;
     manufacturer_ = ModalityManufacturer_Generic;
 
-    SetTimeout(10); 
+    SetTimeout(defaultTimeout_);
     pimpl_->net_ = NULL;
     pimpl_->params_ = NULL;
     pimpl_->assoc_ = NULL;
@@ -957,6 +963,7 @@ namespace Orthanc
 
   void DicomUserConnection::Store(const char* buffer, 
                                   size_t size,
+                                  const std::string& moveOriginatorAET,
                                   uint16_t moveOriginatorID)
   {
     // Prepare an input stream for the memory buffer
@@ -965,24 +972,26 @@ namespace Orthanc
       is.setBuffer(buffer, size);
     is.setEos();
       
-    pimpl_->Store(is, *this, moveOriginatorID);
+    pimpl_->Store(is, *this, moveOriginatorAET, moveOriginatorID);
   }
 
   void DicomUserConnection::Store(const std::string& buffer,
+                                  const std::string& moveOriginatorAET,
                                   uint16_t moveOriginatorID)
   {
     if (buffer.size() > 0)
-      Store(reinterpret_cast<const char*>(&buffer[0]), buffer.size(), moveOriginatorID);
+      Store(reinterpret_cast<const char*>(&buffer[0]), buffer.size(), moveOriginatorAET, moveOriginatorID);
     else
-      Store(NULL, 0, moveOriginatorID);
+      Store(NULL, 0, moveOriginatorAET, moveOriginatorID);
   }
 
   void DicomUserConnection::StoreFile(const std::string& path,
+                                      const std::string& moveOriginatorAET,
                                       uint16_t moveOriginatorID)
   {
     // Prepare an input stream for the file
     DcmInputFileStream is(path.c_str());
-    pimpl_->Store(is, *this, moveOriginatorID);
+    pimpl_->Store(is, *this, moveOriginatorAET, moveOriginatorID);
   }
 
   bool DicomUserConnection::Echo()
@@ -1102,14 +1111,16 @@ namespace Orthanc
 
   void DicomUserConnection::SetTimeout(uint32_t seconds)
   {
-    if (seconds <= 0)
+    if (seconds == 0)
     {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
+      DisableTimeout();
+    }
+    else
+    {
+      dcmConnectionTimeout.set(seconds);
+      pimpl_->dimseTimeout_ = seconds;
+      pimpl_->acseTimeout_ = 10;  // Timeout used during association negociation
     }
-
-    dcmConnectionTimeout.set(seconds);
-    pimpl_->dimseTimeout_ = seconds;
-    pimpl_->acseTimeout_ = 10;
   }
 
 
@@ -1121,7 +1132,7 @@ namespace Orthanc
      */
     dcmConnectionTimeout.set(-1);
     pimpl_->dimseTimeout_ = 0;
-    pimpl_->acseTimeout_ = 10;
+    pimpl_->acseTimeout_ = 10;  // Timeout used during association negociation
   }
 
 
@@ -1191,4 +1202,12 @@ namespace Orthanc
 
     ExecuteFind(result, pimpl_->assoc_, dataset, sopClass, true, NULL, pimpl_->dimseTimeout_);
   }
+
+  
+  void DicomUserConnection::SetDefaultTimeout(uint32_t seconds)
+  {
+    LOG(INFO) << "Default timeout for DICOM connections if Orthanc acts as SCU (client): " 
+              << seconds << " seconds (0 = no timeout)";
+    defaultTimeout_ = seconds;
+  }  
 }
diff --git a/OrthancServer/DicomProtocol/DicomUserConnection.h b/OrthancServer/DicomProtocol/DicomUserConnection.h
index 48ea451..6161578 100644
--- a/OrthancServer/DicomProtocol/DicomUserConnection.h
+++ b/OrthancServer/DicomProtocol/DicomUserConnection.h
@@ -135,14 +135,33 @@ namespace Orthanc
 
     void Store(const char* buffer, 
                size_t size,
+               const std::string& moveOriginatorAET,
                uint16_t moveOriginatorID);
 
+    void Store(const char* buffer, 
+               size_t size)
+    {
+      Store(buffer, size, "", 0);  // Not a C-Move
+    }
+
     void Store(const std::string& buffer,
+               const std::string& moveOriginatorAET,
                uint16_t moveOriginatorID);
 
+    void Store(const std::string& buffer)
+    {
+      Store(buffer, "", 0);  // Not a C-Move
+    }
+
     void StoreFile(const std::string& path,
+                   const std::string& moveOriginatorAET,
                    uint16_t moveOriginatorID);
 
+    void StoreFile(const std::string& path)
+    {
+      StoreFile(path, "", 0);  // Not a C-Move
+    }
+
     void Find(DicomFindAnswers& result,
               ResourceType level,
               const DicomMap& fields);
@@ -175,5 +194,7 @@ namespace Orthanc
 
     void FindWorklist(DicomFindAnswers& result,
                       ParsedDicomFile& query);
+
+    static void SetDefaultTimeout(uint32_t seconds);
   };
 }
diff --git a/OrthancServer/DicomProtocol/IMoveRequestHandler.h b/OrthancServer/DicomProtocol/IMoveRequestHandler.h
index e840e02..44942e6 100644
--- a/OrthancServer/DicomProtocol/IMoveRequestHandler.h
+++ b/OrthancServer/DicomProtocol/IMoveRequestHandler.h
@@ -67,12 +67,12 @@ namespace Orthanc
     {
     }
 
-    virtual IMoveRequestIterator* Handle(const std::string& target,
+    virtual IMoveRequestIterator* Handle(const std::string& targetAet,
                                          const DicomMap& input,
-                                         const std::string& remoteIp,
-                                         const std::string& remoteAet,
+                                         const std::string& originatorIp,
+                                         const std::string& originatorAet,
                                          const std::string& calledAet,
-                                         uint16_t messageId) = 0;
+                                         uint16_t originatorId) = 0;
   };
 
 }
diff --git a/OrthancServer/FromDcmtkBridge.cpp b/OrthancServer/FromDcmtkBridge.cpp
index 921d250..afd33b8 100644
--- a/OrthancServer/FromDcmtkBridge.cpp
+++ b/OrthancServer/FromDcmtkBridge.cpp
@@ -39,8 +39,9 @@
 #include "FromDcmtkBridge.h"
 #include "ToDcmtkBridge.h"
 #include "../Core/Logging.h"
+#include "../Core/SystemToolbox.h"
 #include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
+#include "../Core/TemporaryFile.h"
 #include "../Core/OrthancException.h"
 
 #include <list>
@@ -118,7 +119,7 @@ namespace Orthanc
     std::string content;
     EmbeddedResources::GetFileResource(content, resource);
 
-    Toolbox::TemporaryFile tmp;
+    TemporaryFile tmp;
     tmp.Write(content);
 
     if (!dictionary.loadDictionary(tmp.GetPath().c_str()))
@@ -144,7 +145,6 @@ namespace Orthanc
       throw OrthancException(ErrorCode_InternalError);
     }
   }
-                            
 #endif
 
 
@@ -178,7 +178,7 @@ namespace Orthanc
   }
 
 
-  void FromDcmtkBridge::InitializeDictionary()
+  void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary)
   {
     {
       DictionaryLocker locker;
@@ -195,7 +195,16 @@ namespace Orthanc
       //LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICONDE);
 
       LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICOM);
-      LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_PRIVATE);
+
+      if (loadPrivateDictionary)
+      {
+        LOG(INFO) << "Loading the embedded dictionary of private tags";
+        LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_PRIVATE);
+      }
+      else
+      {
+        LOG(INFO) << "The dictionary of private tags has not been loaded";
+      }
 
 #elif defined(__linux__) || defined(__FreeBSD_kernel__)
       std::string path = DCMTK_DICTIONARY_DIR;
@@ -207,7 +216,15 @@ namespace Orthanc
       }
 
       LoadExternalDictionary(*locker, path, "dicom.dic");
-      LoadExternalDictionary(*locker, path, "private.dic");
+
+      if (loadPrivateDictionary)
+      {
+        LoadExternalDictionary(*locker, path, "private.dic");
+      }
+      else
+      {
+        LOG(INFO) << "The dictionary of private tags has not been loaded";
+      }
 
 #else
 #error Support your platform here
@@ -237,7 +254,8 @@ namespace Orthanc
                                               ValueRepresentation vr,
                                               const std::string& name,
                                               unsigned int minMultiplicity,
-                                              unsigned int maxMultiplicity)
+                                              unsigned int maxMultiplicity,
+                                              const std::string& privateCreator)
   {
     if (minMultiplicity < 1)
     {
@@ -261,20 +279,68 @@ namespace Orthanc
               << name << " (multiplicity: " << minMultiplicity << "-" 
               << (arbitrary ? "n" : boost::lexical_cast<std::string>(maxMultiplicity)) << ")";
 
-    std::auto_ptr<DcmDictEntry>  entry(new DcmDictEntry(tag.GetGroup(),
-                                                        tag.GetElement(),
-                                                        evr, name.c_str(),
-                                                        static_cast<int>(minMultiplicity),
-                                                        static_cast<int>(maxMultiplicity),
-                                                        NULL    /* version */,
-                                                        OFTrue  /* doCopyString */,
-                                                        NULL    /* private creator */));
+    std::auto_ptr<DcmDictEntry>  entry;
+    if (privateCreator.empty())
+    {
+      if (tag.GetGroup() % 2 == 1)
+      {
+        char buf[128];
+        sprintf(buf, "Warning: You are registering a private tag (%04x,%04x), "
+                "but no private creator was associated with it", 
+                tag.GetGroup(), tag.GetElement());
+        LOG(WARNING) << buf;
+      }
+
+      entry.reset(new DcmDictEntry(tag.GetGroup(),
+                                   tag.GetElement(),
+                                   evr, name.c_str(),
+                                   static_cast<int>(minMultiplicity),
+                                   static_cast<int>(maxMultiplicity),
+                                   NULL    /* version */,
+                                   OFTrue  /* doCopyString */,
+                                   NULL    /* private creator */));
+    }
+    else
+    {
+      // "Private Data Elements have an odd Group Number that is not
+      // (0001,eeee), (0003,eeee), (0005,eeee), (0007,eeee), or
+      // (FFFF,eeee)."
+      if (tag.GetGroup() % 2 == 0 /* even */ ||
+          tag.GetGroup() == 0x0001 ||
+          tag.GetGroup() == 0x0003 ||
+          tag.GetGroup() == 0x0005 ||
+          tag.GetGroup() == 0x0007 ||
+          tag.GetGroup() == 0xffff)
+      {
+        char buf[128];
+        sprintf(buf, "Trying to register private tag (%04x,%04x), but it must have an odd group >= 0x0009",
+                tag.GetGroup(), tag.GetElement());
+        LOG(ERROR) << buf;
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+
+      entry.reset(new DcmDictEntry(tag.GetGroup(),
+                                   tag.GetElement(),
+                                   evr, name.c_str(),
+                                   static_cast<int>(minMultiplicity),
+                                   static_cast<int>(maxMultiplicity),
+                                   "private" /* version */,
+                                   OFTrue    /* doCopyString */,
+                                   privateCreator.c_str()));
+    }
 
     entry->setGroupRangeRestriction(DcmDictRange_Unspecified);
     entry->setElementRangeRestriction(DcmDictRange_Unspecified);
 
     {
       DictionaryLocker locker;
+
+      if (locker->findEntry(name.c_str()))
+      {
+        LOG(ERROR) << "Cannot register two tags with the same symbolic name \"" << name << "\"";
+        throw OrthancException(ErrorCode_AlreadyExistingTag);
+      }
+
       locker->addEntry(entry.release());
     }
   }
@@ -314,10 +380,10 @@ namespace Orthanc
   }
 
 
-  void FromDcmtkBridge::Convert(DicomMap& target, 
-                                DcmItem& dataset,
-                                unsigned int maxStringLength,
-                                Encoding defaultEncoding)
+  void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target, 
+                                            DcmItem& dataset,
+                                            unsigned int maxStringLength,
+                                            Encoding defaultEncoding)
   {
     Encoding encoding = DetectEncoding(dataset, defaultEncoding);
 
@@ -374,7 +440,7 @@ namespace Orthanc
         if (maxStringLength != 0 &&
             utf8.size() > maxStringLength)
         {
-          return new DicomValue;  // Create a NULL value
+          return new DicomValue;  // Too long, create a NULL value
         }
         else
         {
@@ -383,6 +449,47 @@ namespace Orthanc
       }
     }
 
+
+    if (element.getVR() == EVR_UN)
+    {
+      // Unknown value representation: Lookup in the dictionary. This
+      // is notably the case for private tags registered with the
+      // "Dictionary" configuration option.
+      DictionaryLocker locker;
+      
+      const DcmDictEntry* entry = locker->findEntry(element.getTag().getXTag(), 
+                                                    element.getTag().getPrivateCreator());
+      if (entry != NULL && 
+          entry->getVR().isaString())
+      {
+        Uint8* data = NULL;
+
+        // At (*), we do not try and convert to UTF-8, as nothing says
+        // the encoding of the private tag is the same as that of the
+        // remaining of the DICOM dataset. Only go for ASCII strings.
+
+        if (element.getUint8Array(data) == EC_Normal &&
+            Toolbox::IsAsciiString(data, element.getLength()))   // (*)
+        {
+          if (data == NULL)
+          {
+            return new DicomValue("", false);   // Empty string
+          }
+          else if (maxStringLength != 0 &&
+                   element.getLength() > maxStringLength)
+          {
+            return new DicomValue;  // Too long, create a NULL value
+          }
+          else
+          {
+            std::string s(reinterpret_cast<const char*>(data), element.getLength());
+            return new DicomValue(s, false);
+          }
+        }
+      }
+    }
+
+
     try
     {
       // http://support.dcmtk.org/docs/dcvr_8h-source.html
@@ -429,7 +536,7 @@ namespace Orthanc
         }
     
         /**
-         * Numberic types
+         * Numeric types
          **/ 
       
         case EVR_SL:  // signed long
@@ -571,8 +678,7 @@ namespace Orthanc
     }
 
     // This code gives access to the name of the private tags
-    DcmTag tagbis(element.getTag());
-    const std::string tagName(tagbis.getTagName());      
+    std::string tagName = FromDcmtkBridge::GetTagName(element);
     
     switch (format)
     {
@@ -589,9 +695,9 @@ namespace Orthanc
         {
           node["Name"] = tagName;
 
-          if (tagbis.getPrivateCreator() != NULL)
+          if (element.getTag().getPrivateCreator() != NULL)
           {
-            node["PrivateCreator"] = tagbis.getPrivateCreator();
+            node["PrivateCreator"] = element.getTag().getPrivateCreator();
           }
 
           return node;
@@ -693,20 +799,12 @@ namespace Orthanc
   }                              
 
 
-  static void DatasetToJson(Json::Value& parent,
-                            DcmItem& item,
-                            DicomToJsonFormat format,
-                            DicomToJsonFlags flags,
-                            unsigned int maxStringLength,
-                            Encoding encoding);
-
-
-  void FromDcmtkBridge::ToJson(Json::Value& parent,
-                               DcmElement& element,
-                               DicomToJsonFormat format,
-                               DicomToJsonFlags flags,
-                               unsigned int maxStringLength,
-                               Encoding encoding)
+  void FromDcmtkBridge::ElementToJson(Json::Value& parent,
+                                      DcmElement& element,
+                                      DicomToJsonFormat format,
+                                      DicomToJsonFlags flags,
+                                      unsigned int maxStringLength,
+                                      Encoding encoding)
   {
     if (parent.type() == Json::nullValue)
     {
@@ -718,7 +816,8 @@ namespace Orthanc
 
     if (element.isLeaf())
     {
-      std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(element, flags, maxStringLength, encoding));
+      // The "0" below lets "LeafValueToJson()" take care of "TooLong" values
+      std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(element, flags, 0, encoding));
       LeafValueToJson(target, *v, format, flags, maxStringLength);
     }
     else
@@ -741,12 +840,12 @@ namespace Orthanc
   }
 
 
-  static void DatasetToJson(Json::Value& parent,
-                            DcmItem& item,
-                            DicomToJsonFormat format,
-                            DicomToJsonFlags flags,
-                            unsigned int maxStringLength,
-                            Encoding encoding)
+  void FromDcmtkBridge::DatasetToJson(Json::Value& parent,
+                                      DcmItem& item,
+                                      DicomToJsonFormat format,
+                                      DicomToJsonFlags flags,
+                                      unsigned int maxStringLength,
+                                      Encoding encoding)
   {
     assert(parent.type() == Json::objectValue);
 
@@ -791,47 +890,53 @@ namespace Orthanc
         }
       }
 
-      FromDcmtkBridge::ToJson(parent, *element, format, flags, maxStringLength, encoding);
+      FromDcmtkBridge::ElementToJson(parent, *element, format, flags, maxStringLength, encoding);
     }
   }
 
 
-  void FromDcmtkBridge::ToJson(Json::Value& target, 
-                               DcmDataset& dataset,
-                               DicomToJsonFormat format,
-                               DicomToJsonFlags flags,
-                               unsigned int maxStringLength,
-                               Encoding defaultEncoding)
+  void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target, 
+                                           DcmDataset& dataset,
+                                           DicomToJsonFormat format,
+                                           DicomToJsonFlags flags,
+                                           unsigned int maxStringLength,
+                                           Encoding defaultEncoding)
   {
+    Encoding encoding = DetectEncoding(dataset, defaultEncoding);
+
     target = Json::objectValue;
-    DatasetToJson(target, dataset, format, flags, maxStringLength, DetectEncoding(dataset, defaultEncoding));
+    DatasetToJson(target, dataset, format, flags, maxStringLength, encoding);
   }
 
 
-  void FromDcmtkBridge::ToJson(Json::Value& target, 
-                               DcmMetaInfo& dataset,
-                               DicomToJsonFormat format,
-                               DicomToJsonFlags flags,
-                               unsigned int maxStringLength)
+  void FromDcmtkBridge::ExtractHeaderAsJson(Json::Value& target, 
+                                            DcmMetaInfo& dataset,
+                                            DicomToJsonFormat format,
+                                            DicomToJsonFlags flags,
+                                            unsigned int maxStringLength)
   {
     target = Json::objectValue;
     DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii);
   }
 
 
-  std::string FromDcmtkBridge::GetName(const DicomTag& t)
+
+  static std::string GetTagNameInternal(DcmTag& tag)
   {
-    // Some patches for important tags because of different DICOM
-    // dictionaries between DCMTK versions
-    std::string n = t.GetMainTagsName();
-    if (n.size() != 0)
     {
-      return n;
+      // Some patches for important tags because of different DICOM
+      // dictionaries between DCMTK versions
+      DicomTag tmp(tag.getGroup(), tag.getElement());
+      std::string n = tmp.GetMainTagsName();
+      if (n.size() != 0)
+      {
+        return n;
+      }
+      // End of patches
     }
-    // End of patches
 
 #if 0
-    DcmTagKey tag(t.GetGroup(), t.GetElement());
+    // This version explicitly calls the dictionary
     const DcmDataDictionary& dict = dcmDataDict.rdlock();
     const DcmDictEntry* entry = dict.findEntry(tag, NULL);
 
@@ -844,7 +949,6 @@ namespace Orthanc
     dcmDataDict.unlock();
     return s;
 #else
-    DcmTag tag(t.GetGroup(), t.GetElement());
     const char* name = tag.getTagName();
     if (name == NULL)
     {
@@ -858,6 +962,31 @@ namespace Orthanc
   }
 
 
+  std::string FromDcmtkBridge::GetTagName(const DicomTag& t,
+                                          const std::string& privateCreator)
+  {
+    DcmTag tag(t.GetGroup(), t.GetElement());
+
+    if (!privateCreator.empty())
+    {
+      tag.setPrivateCreator(privateCreator.c_str());
+    }
+
+    return GetTagNameInternal(tag);
+  }
+
+
+  std::string FromDcmtkBridge::GetTagName(const DcmElement& element)
+  {
+    // Copy the tag to ensure const-correctness of DcmElement. Note
+    // that the private creator information is also copied.
+    DcmTag tag(element.getTag());  
+
+    return GetTagNameInternal(tag);
+  }
+
+
+
   DicomTag FromDcmtkBridge::ParseTag(const char* name)
   {
     if (strlen(name) == 9 &&
@@ -942,23 +1071,26 @@ namespace Orthanc
     for (DicomMap::Map::const_iterator 
            it = values.map_.begin(); it != values.map_.end(); ++it)
     {
+      // TODO Inject PrivateCreator if some is available in the DicomMap?
+      const std::string tagName = GetTagName(it->first, "");
+
       if (simplify)
       {
         if (it->second->IsNull())
         {
-          result[GetName(it->first)] = Json::nullValue;
+          result[tagName] = Json::nullValue;
         }
         else
         {
           // TODO IsBinary
-          result[GetName(it->first)] = it->second->GetContent();
+          result[tagName] = it->second->GetContent();
         }
       }
       else
       {
         Json::Value value = Json::objectValue;
 
-        value["Name"] = GetName(it->first);
+        value["Name"] = tagName;
 
         if (it->second->IsNull())
         {
@@ -988,7 +1120,7 @@ namespace Orthanc
         // The "PatientID" field is of type LO (Long String), 64
         // Bytes Maximum. An UUID is of length 36, thus it can be used
         // as a random PatientID.
-        return Toolbox::GenerateUuid();
+        return SystemToolbox::GenerateUuid();
 
       case ResourceType_Instance:
         return dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT);
@@ -1514,7 +1646,9 @@ namespace Orthanc
 
     if (!ok)
     {
-      throw OrthancException(ErrorCode_InternalError);
+      LOG(ERROR) << "While creating a DICOM instance, tag (" << tag.Format()
+                 << ") has out-of-range value: \"" << *decoded << "\"";
+      throw OrthancException(ErrorCode_BadFileFormat);
     }
   }
 
@@ -1533,6 +1667,11 @@ namespace Orthanc
         FillElementWithString(*element, tag, value.asString(), decodeDataUriScheme, dicomEncoding);
         break;
 
+      case Json::nullValue:
+        element.reset(CreateElementForTag(tag));
+        FillElementWithString(*element, tag, "", decodeDataUriScheme, dicomEncoding);
+        break;
+
       case Json::arrayValue:
       {
         DcmTag key(tag.GetGroup(), tag.GetElement());
@@ -1610,11 +1749,17 @@ namespace Orthanc
       {
         const Json::Value& value = json[tags[i]];
         if (value.type() != Json::stringValue ||
-            !GetDicomEncoding(encoding, value.asCString()))
+            (value.asString().length() != 0 &&
+             !GetDicomEncoding(encoding, value.asCString())))
         {
           LOG(ERROR) << "Unknown encoding while creating DICOM from JSON: " << value;
           throw OrthancException(ErrorCode_BadRequest);
         }
+
+        if (value.asString().length() == 0)
+        {
+          return defaultEncoding;
+        }
       }
     }
 
@@ -1765,4 +1910,106 @@ namespace Orthanc
       target.SetValue(ParseTag(members[i]), value.asString(), false);
     }
   }
+
+
+  void FromDcmtkBridge::ChangeStringEncoding(DcmItem& dataset,
+                                             Encoding source,
+                                             Encoding target)
+  {
+    // Recursive exploration of a dataset to change the encoding of
+    // each string-like element
+
+    if (source == target)
+    {
+      return;
+    }
+
+    for (unsigned long i = 0; i < dataset.card(); i++)
+    {
+      DcmElement* element = dataset.getElement(i);
+      if (element)
+      {
+        if (element->isLeaf())
+        {
+          char *c = NULL;
+          if (element->isaString() &&
+              element->getString(c).good() && 
+              c != NULL)
+          {
+            std::string a = Toolbox::ConvertToUtf8(c, source);
+            std::string b = Toolbox::ConvertFromUtf8(a, target);
+            element->putString(b.c_str());
+          }
+        }
+        else
+        {
+          // "All subclasses of DcmElement except for DcmSequenceOfItems
+          // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset
+          // etc. are not." The following dynamic_cast is thus OK.
+          DcmSequenceOfItems& sequence = dynamic_cast<DcmSequenceOfItems&>(*element);
+
+          for (unsigned long j = 0; j < sequence.card(); j++)
+          {
+            ChangeStringEncoding(*sequence.getItem(j), source, target);
+          }
+        }
+      }
+    }
+  }
+
+
+  bool FromDcmtkBridge::LookupTransferSyntax(std::string& result,
+                                             DcmFileFormat& dicom)
+  {
+    const char* value = NULL;
+
+    if (dicom.getMetaInfo() != NULL &&
+        dicom.getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, value).good() &&
+        value != NULL)
+    {
+      result.assign(value);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+  void FromDcmtkBridge::ExecuteToDicom(DicomMap& target,
+                                       LuaFunctionCall& call)
+  {
+    Json::Value output;
+    call.ExecuteToJson(output, true /* keep strings */);
+
+    target.Clear();
+
+    if (output.type() == Json::arrayValue &&
+        output.size() == 0)
+    {
+      // This case happens for empty tables
+      return;
+    }
+
+    if (output.type() != Json::objectValue)
+    {
+      LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table";
+      throw OrthancException(ErrorCode_LuaBadOutput);
+    }
+
+    Json::Value::Members members = output.getMemberNames();
+
+    for (size_t i = 0; i < members.size(); i++)
+    {
+      if (output[members[i]].type() != Json::stringValue)
+      {
+        LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table mapping names of DICOM tags to strings";
+        throw OrthancException(ErrorCode_LuaBadOutput);
+      }
+
+      DicomTag tag(ParseTag(members[i]));
+      target.SetValue(tag, output[members[i]].asString(), false);
+    }
+  }
 }
diff --git a/OrthancServer/FromDcmtkBridge.h b/OrthancServer/FromDcmtkBridge.h
index eff3b81..d7ee001 100644
--- a/OrthancServer/FromDcmtkBridge.h
+++ b/OrthancServer/FromDcmtkBridge.h
@@ -34,7 +34,9 @@
 
 #include "ServerEnumerations.h"
 
+#include "../Core/DicomFormat/DicomElement.h"
 #include "../Core/DicomFormat/DicomMap.h"
+#include "../Core/Lua/LuaFunctionCall.h"
 
 #include <dcmtk/dcmdata/dcdatset.h>
 #include <dcmtk/dcmdata/dcmetinf.h>
@@ -42,27 +44,68 @@
 #include <dcmtk/dcmdata/dcfilefo.h>
 #include <json/json.h>
 
+#if ORTHANC_BUILD_UNIT_TESTS == 1
+#  include <gtest/gtest_prod.h>
+#endif
+
+
 namespace Orthanc
 {
-  class FromDcmtkBridge
+  class FromDcmtkBridge : public boost::noncopyable
   {
+#if ORTHANC_BUILD_UNIT_TESTS == 1
+    FRIEND_TEST(FromDcmtkBridge, FromJson);
+#endif
+
+    friend class ParsedDicomFile;
+    friend class Configuration;
+
+  private:
+    FromDcmtkBridge();  // Pure static class
+
+    static void ExtractDicomSummary(DicomMap& target, 
+                                    DcmItem& dataset,
+                                    unsigned int maxStringLength,
+                                    Encoding defaultEncoding);
+
+    static void DatasetToJson(Json::Value& parent,
+                              DcmItem& item,
+                              DicomToJsonFormat format,
+                              DicomToJsonFlags flags,
+                              unsigned int maxStringLength,
+                              Encoding encoding);
+
+    static void ElementToJson(Json::Value& parent,
+                              DcmElement& element,
+                              DicomToJsonFormat format,
+                              DicomToJsonFlags flags,
+                              unsigned int maxStringLength,
+                              Encoding dicomEncoding);
+
+    static void ExtractDicomAsJson(Json::Value& target, 
+                                   DcmDataset& dataset,
+                                   DicomToJsonFormat format,
+                                   DicomToJsonFlags flags,
+                                   unsigned int maxStringLength,
+                                   Encoding defaultEncoding);
+
+    static void ChangeStringEncoding(DcmItem& dataset,
+                                     Encoding source,
+                                     Encoding target);
+
   public:
-    static void InitializeDictionary();
+    static void InitializeDictionary(bool loadPrivateDictionary);
 
     static void RegisterDictionaryTag(const DicomTag& tag,
                                       ValueRepresentation vr,
                                       const std::string& name,
                                       unsigned int minMultiplicity,
-                                      unsigned int maxMultiplicity);
+                                      unsigned int maxMultiplicity,
+                                      const std::string& privateCreator);
 
     static Encoding DetectEncoding(DcmItem& dataset,
                                    Encoding defaultEncoding);
 
-    static void Convert(DicomMap& target, 
-                        DcmItem& dataset,
-                        unsigned int maxStringLength,
-                        Encoding defaultEncoding);
-
     static DicomTag Convert(const DcmTag& tag);
 
     static DicomTag GetTag(const DcmElement& element);
@@ -74,27 +117,21 @@ namespace Orthanc
                                           unsigned int maxStringLength,
                                           Encoding encoding);
 
-    static void ToJson(Json::Value& parent,
-                       DcmElement& element,
-                       DicomToJsonFormat format,
-                       DicomToJsonFlags flags,
-                       unsigned int maxStringLength,
-                       Encoding dicomEncoding);
+    static void ExtractHeaderAsJson(Json::Value& target, 
+                                    DcmMetaInfo& header,
+                                    DicomToJsonFormat format,
+                                    DicomToJsonFlags flags,
+                                    unsigned int maxStringLength);
 
-    static void ToJson(Json::Value& target, 
-                       DcmDataset& dataset,
-                       DicomToJsonFormat format,
-                       DicomToJsonFlags flags,
-                       unsigned int maxStringLength,
-                       Encoding defaultEncoding);
+    static std::string GetTagName(const DicomTag& tag,
+                                  const std::string& privateCreator);
 
-    static void ToJson(Json::Value& target, 
-                       DcmMetaInfo& header,
-                       DicomToJsonFormat format,
-                       DicomToJsonFlags flags,
-                       unsigned int maxStringLength);
+    static std::string GetTagName(const DcmElement& element);
 
-    static std::string GetName(const DicomTag& tag);
+    static std::string GetTagName(const DicomElement& element)
+    {
+      return GetTagName(element.GetTag(), "");
+    }
 
     static DicomTag ParseTag(const char* name);
 
@@ -163,5 +200,11 @@ namespace Orthanc
 
     static void FromJson(DicomMap& values,
                          const Json::Value& result);
+
+    static bool LookupTransferSyntax(std::string& result,
+                                     DcmFileFormat& dicom);
+
+    static void ExecuteToDicom(DicomMap& target,
+                               LuaFunctionCall& call);
   };
 }
diff --git a/OrthancServer/Internals/CommandDispatcher.cpp b/OrthancServer/Internals/CommandDispatcher.cpp
index 7b56db5..a29690b 100644
--- a/OrthancServer/Internals/CommandDispatcher.cpp
+++ b/OrthancServer/Internals/CommandDispatcher.cpp
@@ -381,7 +381,6 @@ namespace Orthanc
 
     OFCondition AssociationCleanup(T_ASC_Association *assoc)
     {
-      OFString temp_str;
       OFCondition cond = ASC_dropSCPAssociation(assoc);
       if (cond.bad())
       {
@@ -695,6 +694,38 @@ namespace Orthanc
       return new CommandDispatcher(server, assoc, remoteIp, remoteAet, calledAet, filter);
     }
 
+
+    CommandDispatcher::CommandDispatcher(const DicomServer& server,
+                                         T_ASC_Association* assoc,
+                                         const std::string& remoteIp,
+                                         const std::string& remoteAet,
+                                         const std::string& calledAet,
+                                         IApplicationEntityFilter* filter) :
+      server_(server),
+      assoc_(assoc),
+      remoteIp_(remoteIp),
+      remoteAet_(remoteAet),
+      calledAet_(calledAet),
+      filter_(filter)
+    {
+      associationTimeout_ = server.GetAssociationTimeout();
+      elapsedTimeSinceLastCommand_ = 0;
+    }
+
+
+    CommandDispatcher::~CommandDispatcher()
+    {
+      try
+      {
+        AssociationCleanup(assoc_);
+      }
+      catch (...)
+      {
+        LOG(ERROR) << "Some association was not cleanly aborted";
+      }
+    }
+
+
     bool CommandDispatcher::Step()
     /*
      * This function receives DIMSE commmands over the network connection
@@ -727,16 +758,16 @@ namespace Orthanc
       else if (cond == DIMSE_NODATAAVAILABLE)
       {
         // Timeout due to DIMSE_NONBLOCKING
-        if (clientTimeout_ != 0 && 
-            elapsedTimeSinceLastCommand_ >= clientTimeout_)
+        if (associationTimeout_ != 0 && 
+            elapsedTimeSinceLastCommand_ >= associationTimeout_)
         {
-          // This timeout is actually a client timeout
+          // This timeout is actually a association timeout
           finished = true;
         }
       }
       else if (cond == EC_Normal)
       {
-        // Reset the client timeout counter
+        // Reset the association timeout counter
         elapsedTimeSinceLastCommand_ = 0;
 
         // Convert the type of request to Orthanc's internal type
diff --git a/OrthancServer/Internals/CommandDispatcher.h b/OrthancServer/Internals/CommandDispatcher.h
index 35dd970..eeb8559 100644
--- a/OrthancServer/Internals/CommandDispatcher.h
+++ b/OrthancServer/Internals/CommandDispatcher.h
@@ -46,7 +46,7 @@ namespace Orthanc
     class CommandDispatcher : public IRunnableBySteps
     {
     private:
-      uint32_t clientTimeout_;
+      uint32_t associationTimeout_;
       uint32_t elapsedTimeSinceLastCommand_;
       const DicomServer& server_;
       T_ASC_Association* assoc_;
@@ -61,22 +61,9 @@ namespace Orthanc
                         const std::string& remoteIp,
                         const std::string& remoteAet,
                         const std::string& calledAet,
-                        IApplicationEntityFilter* filter) :
-        server_(server),
-        assoc_(assoc),
-        remoteIp_(remoteIp),
-        remoteAet_(remoteAet),
-        calledAet_(calledAet),
-        filter_(filter)
-      {
-        clientTimeout_ = server.GetClientTimeout();
-        elapsedTimeSinceLastCommand_ = 0;
-      }
+                        IApplicationEntityFilter* filter);
 
-      virtual ~CommandDispatcher()
-      {
-        AssociationCleanup(assoc_);
-      }
+      virtual ~CommandDispatcher();
 
       virtual bool Step();
     };
diff --git a/OrthancServer/Internals/DicomFrameIndex.cpp b/OrthancServer/Internals/DicomFrameIndex.cpp
index c157656..8e8aaf4 100644
--- a/OrthancServer/Internals/DicomFrameIndex.cpp
+++ b/OrthancServer/Internals/DicomFrameIndex.cpp
@@ -404,8 +404,7 @@ namespace Orthanc
 
     // Extract information about the image structure
     DicomMap tags;
-    FromDcmtkBridge::Convert(tags, dataset, ORTHANC_MAXIMUM_TAG_LENGTH,
-                             Configuration::GetDefaultEncoding());
+    Configuration::ExtractDicomSummary(tags, dataset);
 
     DicomImageInformation information(tags);
 
diff --git a/OrthancServer/Internals/DicomImageDecoder.cpp b/OrthancServer/Internals/DicomImageDecoder.cpp
index a78bea8..6165090 100644
--- a/OrthancServer/Internals/DicomImageDecoder.cpp
+++ b/OrthancServer/Internals/DicomImageDecoder.cpp
@@ -94,13 +94,13 @@
 #include <dcmtk/dcmdata/dcrleccd.h>
 #include <dcmtk/dcmdata/dcrlecp.h>
 
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
 #  include <dcmtk/dcmjpls/djcodecd.h>
 #  include <dcmtk/dcmjpls/djcparam.h>
 #  include <dcmtk/dcmjpeg/djrplol.h>
 #endif
 
-#if ORTHANC_JPEG_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG == 1
 #  include <dcmtk/dcmjpeg/djcodecd.h>
 #  include <dcmtk/dcmjpeg/djcparam.h>
 #  include <dcmtk/dcmjpeg/djdecbas.h>
@@ -250,8 +250,7 @@ namespace Orthanc
       // See also: http://support.dcmtk.org/wiki/dcmtk/howto/accessing-compressed-data
 
       DicomMap m;
-      FromDcmtkBridge::Convert(m, dataset, ORTHANC_MAXIMUM_TAG_LENGTH,
-                               Configuration::GetDefaultEncoding());
+      Configuration::ExtractDicomSummary(m, dataset);
 
       /**
        * Create an accessor to the raw values of the DICOM image.
@@ -323,8 +322,7 @@ namespace Orthanc
                                                 bool ignorePhotometricInterpretation)
   {
     DicomMap m;
-    FromDcmtkBridge::Convert(m, dataset, ORTHANC_MAXIMUM_TAG_LENGTH,
-                             Configuration::GetDefaultEncoding());
+    Configuration::ExtractDicomSummary(m, dataset);
 
     DicomImageInformation info(m);
     PixelFormat format;
@@ -340,7 +338,7 @@ namespace Orthanc
       throw OrthancException(ErrorCode_NotImplemented);
     }
 
-    return new Image(format, info.GetWidth(), info.GetHeight());
+    return new Image(format, info.GetWidth(), info.GetHeight(), false);
   }
 
 
@@ -519,7 +517,7 @@ namespace Orthanc
     }
 
 
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
     /**
      * Deal with JPEG-LS images.
      **/
@@ -551,7 +549,7 @@ namespace Orthanc
 #endif
 
 
-#if ORTHANC_JPEG_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG == 1
     /**
      * Deal with JPEG images.
      **/
@@ -674,7 +672,7 @@ namespace Orthanc
     if (image->GetFormat() != format)
     {
       // A conversion is required
-      std::auto_ptr<ImageAccessor> target(new Image(format, image->GetWidth(), image->GetHeight()));
+      std::auto_ptr<ImageAccessor> target(new Image(format, image->GetWidth(), image->GetHeight(), false));
       ImageProcessing::Convert(*target, *image);
       image = target;
     }
@@ -713,7 +711,7 @@ namespace Orthanc
         // If the source image is not grayscale 8bpp, convert it
         if (image->GetFormat() != PixelFormat_Grayscale8)
         {
-          std::auto_ptr<ImageAccessor> target(new Image(PixelFormat_Grayscale8, image->GetWidth(), image->GetHeight()));
+          std::auto_ptr<ImageAccessor> target(new Image(PixelFormat_Grayscale8, image->GetWidth(), image->GetHeight(), false));
           ImageProcessing::Convert(*target, *image);
           image = target;
         }
diff --git a/OrthancServer/Internals/DicomImageDecoder.h b/OrthancServer/Internals/DicomImageDecoder.h
index 9c1d752..97a9278 100644
--- a/OrthancServer/Internals/DicomImageDecoder.h
+++ b/OrthancServer/Internals/DicomImageDecoder.h
@@ -36,6 +36,15 @@
 
 #include <memory>
 
+#if !defined(ORTHANC_ENABLE_JPEG)
+#  error The macro ORTHANC_ENABLE_JPEG must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_JPEG_LOSSLESS)
+#  error The macro ORTHANC_ENABLE_JPEG_LOSSLESS must be defined
+#endif
+
+
 class DcmDataset;
 class DcmCodec;
 class DcmCodecParameter;
diff --git a/OrthancServer/Internals/FindScp.cpp b/OrthancServer/Internals/FindScp.cpp
index da96e1f..b3a52e0 100644
--- a/OrthancServer/Internals/FindScp.cpp
+++ b/OrthancServer/Internals/FindScp.cpp
@@ -89,6 +89,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../OrthancInitialization.h"
 
 #include <dcmtk/dcmdata/dcfilefo.h>
+#include <dcmtk/dcmdata/dcdeftag.h>
+
+
+
+/**
+ * The function below is extracted from DCMTK 3.6.0, cf. file
+ * "dcmtk-3.6.0/dcmwlm/libsrc/wldsfs.cc".
+ **/
+
+static void HandleExistentButEmptyReferencedStudyOrPatientSequenceAttributes(DcmDataset *dataset, 
+                                                                             const DcmTagKey &sequenceTagKey)
+// Date         : May 3, 2005
+// Author       : Thomas Wilkens
+// Task         : This function performs a check on a sequence attribute in the given dataset. At two different places
+//                in the definition of the DICOM worklist management service, a sequence attribute with a return type
+//                of 2 is mentioned containing two 1C attributes in its item; the condition of the two 1C attributes
+//                specifies that in case a sequence item is present, then these two attributes must be existent and
+//                must contain a value. (I am talking about ReferencedStudySequence and ReferencedPatientSequence.)
+//                In cases where the sequence attribute contains exactly one item with an empty ReferencedSOPClass
+//                and an empty ReferencedSOPInstance, we want to remove the item from the sequence. This is what
+//                this function does.
+// Parameters   : dataset         - [in] Dataset in which the consistency of the sequence attribute shall be checked.
+//                sequenceTagKey  - [in] DcmTagKey of the sequence attribute which shall be checked.
+// Return Value : none.
+{
+  DcmElement *sequenceAttribute = NULL, *referencedSOPClassUIDAttribute = NULL, *referencedSOPInstanceUIDAttribute = NULL;
+
+  // in case the sequence attribute contains exactly one item with an empty
+  // ReferencedSOPClassUID and an empty ReferencedSOPInstanceUID, remove the item
+  if( dataset->findAndGetElement( sequenceTagKey, sequenceAttribute ).good() &&
+      ( (DcmSequenceOfItems*)sequenceAttribute )->card() == 1 &&
+      ( (DcmSequenceOfItems*)sequenceAttribute )->getItem(0)->findAndGetElement( DCM_ReferencedSOPClassUID, referencedSOPClassUIDAttribute ).good() &&
+      referencedSOPClassUIDAttribute->getLength() == 0 &&
+      ( (DcmSequenceOfItems*)sequenceAttribute )->getItem(0)->findAndGetElement( DCM_ReferencedSOPInstanceUID, referencedSOPInstanceUIDAttribute, OFFalse ).good() &&
+      referencedSOPInstanceUIDAttribute->getLength() == 0 )
+  {
+    DcmItem *item = ((DcmSequenceOfItems*)sequenceAttribute)->remove( ((DcmSequenceOfItems*)sequenceAttribute)->getItem(0) );
+    delete item;
+  }
+}
+
+
 
 namespace Orthanc
 {
@@ -103,9 +145,27 @@ namespace Orthanc
       const std::string* remoteIp_;
       const std::string* remoteAet_;
       const std::string* calledAet_;
+
+      FindScpData() : answers_(false)
+      {
+      }
     };
 
 
+
+    static void FixWorklistQuery(ParsedDicomFile& query)
+    {
+      // TODO: Check out
+      // WlmDataSourceFileSystem::HandleExistentButEmptyDescriptionAndCodeSequenceAttributes()"
+      // in DCMTK 3.6.0
+
+      DcmDataset* dataset = query.GetDcmtkObject().getDataset();      
+      HandleExistentButEmptyReferencedStudyOrPatientSequenceAttributes(dataset, DCM_ReferencedStudySequence);
+      HandleExistentButEmptyReferencedStudyOrPatientSequenceAttributes(dataset, DCM_ReferencedPatientSequence);
+    }
+
+
+
     void FindScpCallback(
       /* in */ 
       void *callbackData,  
@@ -132,9 +192,13 @@ namespace Orthanc
         {
           if (sopClassUid == UID_FINDModalityWorklistInformationModel)
           {
+            data.answers_.SetWorklist(true);
+
             if (data.worklistHandler_ != NULL)
             {
               ParsedDicomFile query(*requestIdentifiers);
+              FixWorklistQuery(query);
+
               data.worklistHandler_->Handle(data.answers_, query,
                                             *data.remoteIp_, *data.remoteAet_,
                                             *data.calledAet_);
@@ -147,6 +211,8 @@ namespace Orthanc
           }
           else
           {
+            data.answers_.SetWorklist(false);
+
             if (data.findHandler_ != NULL)
             {
               std::list<DicomTag> sequencesToReturn;
@@ -163,7 +229,7 @@ namespace Orthanc
                   {
                     LOG(WARNING) << "Orthanc only supports sequence matching on worklists, "
                                  << "ignoring C-FIND SCU constraint on tag (" << tag.Format() 
-                                 << ") " << FromDcmtkBridge::GetName(tag);
+                                 << ") " << FromDcmtkBridge::GetTagName(*element);
                   }
 
                   sequencesToReturn.push_back(tag);
@@ -171,8 +237,8 @@ namespace Orthanc
               }
 
               DicomMap input;
-              FromDcmtkBridge::Convert(input, *requestIdentifiers, ORTHANC_MAXIMUM_TAG_LENGTH,
-                                       Configuration::GetDefaultEncoding());
+              Configuration::ExtractDicomSummary(input, *requestIdentifiers);
+
               data.findHandler_->Handle(data.answers_, input, sequencesToReturn,
                                         *data.remoteIp_, *data.remoteAet_,
                                         *data.calledAet_);
diff --git a/OrthancServer/Internals/MoveScp.cpp b/OrthancServer/Internals/MoveScp.cpp
index 1b0ba1d..a37b8f5 100644
--- a/OrthancServer/Internals/MoveScp.cpp
+++ b/OrthancServer/Internals/MoveScp.cpp
@@ -90,6 +90,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../../Core/Logging.h"
 #include "../../Core/OrthancException.h"
 
+#include <boost/lexical_cast.hpp>
+
 
 namespace Orthanc
 {
@@ -110,6 +112,42 @@ namespace Orthanc
     };
 
 
+
+    static uint16_t GetMessageId(const DicomMap& message)
+    {
+      /**
+       * Retrieve the Message ID (0000,0110) for this C-MOVE request, if
+       * any. If present, this Message ID will be stored in the Move
+       * Originator Message ID (0000,1031) field of the C-MOVE response.
+       * http://dicom.nema.org/dicom/2013/output/chtml/part07/chapter_E.html
+       **/
+
+      const DicomValue* value = message.TestAndGetValue(DICOM_TAG_MESSAGE_ID);
+
+      if (value != NULL &&
+          !value->IsNull() &&
+          !value->IsBinary())
+      {
+        try
+        {
+          int tmp = boost::lexical_cast<int>(value->GetContent());
+          if (tmp >= 0 && tmp <= 0xffff)
+          {
+            return static_cast<uint16_t>(tmp);
+          }
+        }
+        catch (boost::bad_lexical_cast&)
+        {
+          LOG(WARNING) << "Cannot convert the Message ID (\"" << value->GetContent()
+                       << "\") of an incoming C-MOVE request to an integer, assuming zero";
+        }
+      }
+
+      return 0;
+    }
+
+
+
     void MoveScpCallback(
       /* in */ 
       void *callbackData,  
@@ -130,14 +168,12 @@ namespace Orthanc
       if (data.lastRequest_ == NULL)
       {
         DicomMap input;
-        FromDcmtkBridge::Convert(input, *requestIdentifiers, ORTHANC_MAXIMUM_TAG_LENGTH,
-                                 Configuration::GetDefaultEncoding());
+        Configuration::ExtractDicomSummary(input, *requestIdentifiers);
 
         try
         {
-          data.iterator_.reset(data.handler_->Handle(data.target_, input,
-                                                     *data.remoteIp_, *data.remoteAet_,
-                                                     *data.calledAet_, request->MessageID));
+          data.iterator_.reset(data.handler_->Handle(data.target_, input, *data.remoteIp_, *data.remoteAet_,
+                                                     *data.calledAet_, GetMessageId(input)));
 
           if (data.iterator_.get() == NULL)
           {
diff --git a/OrthancServer/Internals/StoreScp.cpp b/OrthancServer/Internals/StoreScp.cpp
index 2f57b02..30b9025 100644
--- a/OrthancServer/Internals/StoreScp.cpp
+++ b/OrthancServer/Internals/StoreScp.cpp
@@ -168,15 +168,8 @@ namespace Orthanc
 
           try
           {
-            const Encoding defaultEncoding = Configuration::GetDefaultEncoding();
-            FromDcmtkBridge::Convert(summary, **imageDataSet, 
-                                     ORTHANC_MAXIMUM_TAG_LENGTH,
-                                     defaultEncoding);
-            FromDcmtkBridge::ToJson(dicomJson, **imageDataSet,
-                                    DicomToJsonFormat_Full, 
-                                    DicomToJsonFlags_Default, 
-                                    ORTHANC_MAXIMUM_TAG_LENGTH,
-                                    defaultEncoding);
+            Configuration::ExtractDicomSummary(summary, **imageDataSet);
+            Configuration::ExtractDicomAsJson(dicomJson, **imageDataSet);
 
             if (!FromDcmtkBridge::SaveToMemoryBuffer(buffer, **imageDataSet))
             {
@@ -219,7 +212,7 @@ namespace Orthanc
 
                 if (e.GetErrorCode() == ErrorCode_InexistentTag)
                 {
-                  Toolbox::LogMissingRequiredTag(summary);
+                  ServerToolbox::LogMissingRequiredTag(summary);
                 }
                 else
                 {
diff --git a/OrthancServer/LuaScripting.cpp b/OrthancServer/LuaScripting.cpp
index 4d961e2..d80cd0a 100644
--- a/OrthancServer/LuaScripting.cpp
+++ b/OrthancServer/LuaScripting.cpp
@@ -252,9 +252,10 @@ namespace Orthanc
       std::string modality = parameters["Modality"].asString();
       LOG(INFO) << "Lua script to send resource " << parameters["Resource"].asString()
                 << " to modality " << modality << " using Store-SCU";
+
+      // This is not a C-MOVE: No need to call "StoreScuCommand::SetMoveOriginator()"
       return new StoreScuCommand(context_, localAet,
-                                 Configuration::GetModalityUsingSymbolicName(modality), 
-                                 true, 0 /* not a C-MOVE */);
+                                 Configuration::GetModalityUsingSymbolicName(modality), true);
     }
 
     if (operation == "store-peer")
diff --git a/OrthancServer/OrthancFindRequestHandler.cpp b/OrthancServer/OrthancFindRequestHandler.cpp
index f451083..2134ff1 100644
--- a/OrthancServer/OrthancFindRequestHandler.cpp
+++ b/OrthancServer/OrthancFindRequestHandler.cpp
@@ -107,10 +107,34 @@ namespace Orthanc
   }
 
 
-  static void ExtractTagFromInstances(std::set<std::string>& target,
-                                      ServerContext& context,
-                                      const DicomTag& tag,
-                                      const std::list<std::string>& instances)
+  static bool ExtractMetadata(std::set<std::string>& target,
+                              ServerIndex& index,
+                              MetadataType metadata,
+                              const std::list<std::string>& resources)
+  {
+    for (std::list<std::string>::const_iterator
+           it = resources.begin(); it != resources.end(); ++it)
+    {
+      std::string value;
+      if (index.LookupMetadata(value, *it, metadata))
+      {
+        target.insert(value);
+      }
+      else
+      {
+        // This metadata is unavailable for some resource, give up
+        return false;
+      }
+    }
+
+    return true;
+  }  
+
+
+  static void ExtractTagFromInstancesOnDisk(std::set<std::string>& target,
+                                            ServerContext& context,
+                                            const DicomTag& tag,
+                                            const std::list<std::string>& instances)
   {
     // WARNING: This function is slow, as it reads the JSON file
     // summarizing each instance of interest from the hard drive.
@@ -121,7 +145,7 @@ namespace Orthanc
            it = instances.begin(); it != instances.end(); ++it)
     {
       Json::Value dicom;
-      context.ReadJson(dicom, *it);
+      context.ReadDicomAsJson(dicom, *it);
 
       if (dicom.isMember(formatted))
       {
@@ -226,10 +250,16 @@ namespace Orthanc
 
     if (query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY))
     {
-      if (Configuration::GetGlobalBoolParameter("AllowFindSopClassesInStudy", false))
+      std::set<std::string> values;
+
+      if (ExtractMetadata(values, index, MetadataType_Instance_SopClassUid, instances))
       {
-        std::set<std::string> values;
-        ExtractTagFromInstances(values, context, DICOM_TAG_SOP_CLASS_UID, instances);
+        // The metadata "SopClassUid" is available for each of these instances
+        StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values);
+      }
+      else if (Configuration::GetGlobalBoolParameter("AllowFindSopClassesInStudy", false))
+      {
+        ExtractTagFromInstancesOnDisk(values, context, DICOM_TAG_SOP_CLASS_UID, instances);
         StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values);
       }
       else
@@ -401,7 +431,7 @@ namespace Orthanc
           for (Json::Value::ArrayIndex i = 0; i < source["Value"].size(); i++)
           {
             Json::Value item;
-            Toolbox::SimplifyTags(item, source["Value"][i], DicomToJsonFormat_Short);
+            ServerToolbox::SimplifyTags(item, source["Value"][i], DicomToJsonFormat_Short);
             content.append(item);
           }
 
@@ -456,62 +486,27 @@ namespace Orthanc
                                                  const std::string& remoteAet,
                                                  const std::string& calledAet)
   {
-    Json::Value output;
+    static const char* LUA_CALLBACK = "IncomingFindRequestFilter";
 
+    LuaScripting::Locker locker(context_.GetLua());
+    if (!locker.GetLua().IsExistingFunction(LUA_CALLBACK))
+    {
+      return false;
+    }
+    else
     {
-      LuaScripting::Locker locker(context_.GetLua());
-      static const char* NAME = "IncomingFindRequestFilter";
-      
-      if (!locker.GetLua().IsExistingFunction(NAME))
-      {
-        return false;
-      }
-
-      Json::Value tmp = Json::objectValue;
-      DicomArray a(source);
-
-      for (size_t i = 0; i < a.GetSize(); i++)
-      {
-        const DicomValue& v = a.GetElement(i).GetValue();
-        std::string s = (v.IsNull() || v.IsBinary()) ? "" : v.GetContent();
-        tmp[a.GetElement(i).GetTag().Format()] = s;
-      }
-
       Json::Value origin = Json::objectValue;
       origin["RemoteIp"] = remoteIp;
       origin["RemoteAet"] = remoteAet;
       origin["CalledAet"] = calledAet;
 
-      LuaFunctionCall call(locker.GetLua(), NAME);
-      call.PushJson(tmp);
+      LuaFunctionCall call(locker.GetLua(), LUA_CALLBACK);
+      call.PushDicom(source);
       call.PushJson(origin);
+      FromDcmtkBridge::ExecuteToDicom(target, call);
 
-      call.ExecuteToJson(output, true);
+      return true;
     }
-
-    // The Lua context is released at this point
-
-    if (output.type() != Json::objectValue)
-    {
-      LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table";
-      throw OrthancException(ErrorCode_LuaBadOutput);
-    }
-
-    Json::Value::Members members = output.getMemberNames();
-
-    for (size_t i = 0; i < members.size(); i++)
-    {
-      if (output[members[i]].type() != Json::stringValue)
-      {
-        LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table mapping names of DICOM tags to strings";
-        throw OrthancException(ErrorCode_LuaBadOutput);
-      }
-
-      DicomTag tag(FromDcmtkBridge::ParseTag(members[i]));
-      target.SetValue(tag, output[members[i]].asString(), false);
-    }
-
-    return true;
   }
 
 
@@ -582,7 +577,7 @@ namespace Orthanc
       if (!query.GetElement(i).GetValue().IsNull())
       {
         LOG(INFO) << "  " << query.GetElement(i).GetTag()
-                  << "  " << FromDcmtkBridge::GetName(query.GetElement(i).GetTag())
+                  << "  " << FromDcmtkBridge::GetTagName(query.GetElement(i))
                   << " = " << query.GetElement(i).GetValue().GetContent();
       }
     }
@@ -591,7 +586,7 @@ namespace Orthanc
          it != sequencesToReturn.end(); ++it)
     {
       LOG(INFO) << "  (" << it->Format()
-                << ")  " << FromDcmtkBridge::GetName(*it)
+                << ")  " << FromDcmtkBridge::GetTagName(*it, "")
                 << " : sequence tag whose content will be copied";
     }
 
@@ -604,16 +599,17 @@ namespace Orthanc
 
     for (size_t i = 0; i < query.GetSize(); i++)
     {
-      const DicomTag tag = query.GetElement(i).GetTag();
+      const DicomElement& element = query.GetElement(i);
+      const DicomTag tag = element.GetTag();
 
-      if (query.GetElement(i).GetValue().IsNull() ||
+      if (element.GetValue().IsNull() ||
           tag == DICOM_TAG_QUERY_RETRIEVE_LEVEL ||
           tag == DICOM_TAG_SPECIFIC_CHARACTER_SET)
       {
         continue;
       }
 
-      std::string value = query.GetElement(i).GetValue().GetContent();
+      std::string value = element.GetValue().GetContent();
       if (value.size() == 0)
       {
         // An empty string corresponds to a "*" wildcard constraint, so we ignore it
@@ -637,7 +633,7 @@ namespace Orthanc
       else
       {
         LOG(INFO) << "Because of a patch for the manufacturer of the remote modality, " 
-                  << "ignoring constraint on tag (" << tag.Format() << ") " << FromDcmtkBridge::GetName(tag);
+                  << "ignoring constraint on tag (" << tag.Format() << ") " << FromDcmtkBridge::GetTagName(element);
       }
     }
 
@@ -651,13 +647,15 @@ namespace Orthanc
     std::vector<std::string> resources, instances;
     context_.GetIndex().FindCandidates(resources, instances, finder);
 
+    LOG(INFO) << "Number of candidate resources after fast DB filtering: " << resources.size();
+
     assert(resources.size() == instances.size());
     bool complete = true;
 
     for (size_t i = 0; i < instances.size(); i++)
     {
       Json::Value dicom;
-      context_.ReadJson(dicom, instances[i]);
+      context_.ReadDicomAsJson(dicom, instances[i]);
       
       if (finder.IsMatch(dicom))
       {
@@ -669,7 +667,7 @@ namespace Orthanc
         }
         else
         {
-          std::auto_ptr<DicomMap> counters(ComputeCounters(context_, instances[i], level, input));
+          std::auto_ptr<DicomMap> counters(ComputeCounters(context_, instances[i], level, *filteredInput));
           AddAnswer(answers, dicom, query, sequencesToReturn, counters.get());
         }
       }
diff --git a/OrthancServer/OrthancInitialization.cpp b/OrthancServer/OrthancInitialization.cpp
index a498a67..a4e2830 100644
--- a/OrthancServer/OrthancInitialization.cpp
+++ b/OrthancServer/OrthancInitialization.cpp
@@ -47,26 +47,16 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/filesystem.hpp>
 #include <curl/curl.h>
-#include <boost/thread.hpp>
+#include <boost/thread/recursive_mutex.hpp>
 
 
-#if ORTHANC_SSL_ENABLED == 1
-// For OpenSSL initialization and finalization
-#include <openssl/conf.h>
-#include <openssl/engine.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/ssl.h>
+#if ORTHANC_ENABLE_JPEG == 1
+#  include <dcmtk/dcmjpeg/djdecode.h>
 #endif
 
 
-#if ORTHANC_JPEG_ENABLED == 1
-#include <dcmtk/dcmjpeg/djdecode.h>
-#endif
-
-
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
-#include <dcmtk/dcmjpls/djdecode.h>
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
+#  include <dcmtk/dcmjpls/djdecode.h>
 #endif
 
 
@@ -138,7 +128,7 @@ namespace Orthanc
 
     {
       std::string content;
-      Toolbox::ReadFile(content, path.string());
+      SystemToolbox::ReadFile(content, path.string());
 
       Json::Value tmp;
       Json::Reader reader;
@@ -404,11 +394,12 @@ namespace Orthanc
       const Json::Value& content = configuration["Dictionary"][tags[i]];
       if (content.type() != Json::arrayValue ||
           content.size() < 2 ||
-          content.size() > 4 ||
+          content.size() > 5 ||
           content[0].type() != Json::stringValue ||
           content[1].type() != Json::stringValue ||
           (content.size() >= 3 && content[2].type() != Json::intValue) ||
-          (content.size() >= 4 && content[3].type() != Json::intValue))
+          (content.size() >= 4 && content[3].type() != Json::intValue) ||
+          (content.size() >= 5 && content[4].type() != Json::stringValue))
       {
         throw OrthancException(ErrorCode_BadFileFormat);
       }
@@ -418,8 +409,9 @@ namespace Orthanc
       std::string name = content[1].asString();
       unsigned int minMultiplicity = (content.size() >= 2) ? content[2].asUInt() : 1;
       unsigned int maxMultiplicity = (content.size() >= 3) ? content[3].asUInt() : 1;
+      std::string privateCreator = (content.size() >= 4) ? content[4].asString() : "";
 
-      FromDcmtkBridge::RegisterDictionaryTag(tag, vr, name, minMultiplicity, maxMultiplicity);
+      FromDcmtkBridge::RegisterDictionaryTag(tag, vr, name, minMultiplicity, maxMultiplicity, privateCreator);
     }
   }
 
@@ -471,13 +463,7 @@ namespace Orthanc
   {
     boost::recursive_mutex::scoped_lock lock(globalMutex_);
 
-#if ORTHANC_SSL_ENABLED == 1
-    // https://wiki.openssl.org/index.php/Library_Initialization
-    SSL_library_init();
-    SSL_load_error_strings();
-    OpenSSL_add_all_algorithms();
-    ERR_load_crypto_strings();
-#endif
+    HttpClient::InitializeOpenSsl();
 
     InitializeServerEnumerations();
 
@@ -495,15 +481,15 @@ namespace Orthanc
     RegisterUserMetadata();
     RegisterUserContentType();
 
-    FromDcmtkBridge::InitializeDictionary();
+    FromDcmtkBridge::InitializeDictionary(GetGlobalBoolParameterInternal("LoadPrivateDictionary", true));
     LoadCustomDictionary(configuration_);
 
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
     LOG(WARNING) << "Registering JPEG Lossless codecs";
     DJLSDecoderRegistration::registerCodecs();    
 #endif
 
-#if ORTHANC_JPEG_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG == 1
     LOG(WARNING) << "Registering JPEG codecs";
     DJDecoderRegistration::registerCodecs(); 
 #endif
@@ -521,27 +507,17 @@ namespace Orthanc
     boost::recursive_mutex::scoped_lock lock(globalMutex_);
     HttpClient::GlobalFinalize();
 
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
     // Unregister JPEG-LS codecs
     DJLSDecoderRegistration::cleanup();
 #endif
 
-#if ORTHANC_JPEG_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG == 1
     // Unregister JPEG codecs
     DJDecoderRegistration::cleanup();
 #endif
 
-#if ORTHANC_SSL_ENABLED == 1
-    // Finalize OpenSSL
-    // https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
-    FIPS_mode_set(0);
-    ENGINE_cleanup();
-    CONF_modules_unload(1);
-    EVP_cleanup();
-    CRYPTO_cleanup_all_ex_data();
-    ERR_remove_state(0);
-    ERR_free_strings();
-#endif
+    HttpClient::FinalizeOpenSsl();
   }
 
 
@@ -577,6 +553,23 @@ namespace Orthanc
   }
 
 
+  unsigned int Configuration::GetGlobalUnsignedIntegerParameter(const std::string& parameter,
+                                                                unsigned int defaultValue)
+  {
+    int v = GetGlobalIntegerParameter(parameter, defaultValue);
+
+    if (v < 0)
+    {
+      LOG(ERROR) << "The configuration option \"" << parameter << "\" must be a positive integer";
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      return static_cast<unsigned int>(v);
+    }
+  }
+
+
   bool Configuration::GetGlobalBoolParameter(const std::string& parameter,
                                              bool defaultValue)
   {
@@ -1118,6 +1111,19 @@ namespace Orthanc
   }
 
 
+  void Configuration::SetDefaultEncoding(Encoding encoding)
+  {
+    std::string name = EnumerationToString(encoding);
+
+    {
+      boost::recursive_mutex::scoped_lock lock(globalMutex_);
+      configuration_["DefaultEncoding"] = name;
+    }
+
+    LOG(INFO) << "Default encoding was changed to: " << name;
+  }
+
+
   bool Configuration::HasConfigurationChanged()
   {
     Json::Value starting;
@@ -1132,4 +1138,21 @@ namespace Orthanc
 
     return a != b;
   }
+
+
+  void Configuration::ExtractDicomSummary(DicomMap& target, 
+                                          DcmItem& dataset)
+  {
+    FromDcmtkBridge::ExtractDicomSummary(target, dataset, 
+                                         ORTHANC_MAXIMUM_TAG_LENGTH, GetDefaultEncoding());
+  }
+
+  
+  void Configuration::ExtractDicomAsJson(Json::Value& target, 
+                                         DcmDataset& dataset)
+  {
+    FromDcmtkBridge::ExtractDicomAsJson(target, dataset, 
+                                        DicomToJsonFormat_Full, DicomToJsonFlags_Default, 
+                                        ORTHANC_MAXIMUM_TAG_LENGTH, GetDefaultEncoding());
+  }
 }
diff --git a/OrthancServer/OrthancInitialization.h b/OrthancServer/OrthancInitialization.h
index b2dc0cc..7218335 100644
--- a/OrthancServer/OrthancInitialization.h
+++ b/OrthancServer/OrthancInitialization.h
@@ -46,6 +46,18 @@
 #include "IDatabaseWrapper.h"
 #include "ServerEnumerations.h"
 
+#if !defined(ORTHANC_ENABLE_JPEG)
+#  error The macro ORTHANC_ENABLE_JPEG must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_JPEG_LOSSLESS)
+#  error The macro ORTHANC_ENABLE_JPEG_LOSSLESS must be defined
+#endif
+
+
+class DcmDataset;
+class DcmItem;
+
 namespace Orthanc
 {
   void OrthancInitialize(const char* configurationFile = NULL);
@@ -64,6 +76,9 @@ namespace Orthanc
     static int GetGlobalIntegerParameter(const std::string& parameter,
                                          int defaultValue);
 
+    static unsigned int GetGlobalUnsignedIntegerParameter(const std::string& parameter,
+                                                          unsigned int defaultValue);
+
     static bool GetGlobalBoolParameter(const std::string& parameter,
                                        bool defaultValue);
 
@@ -123,6 +138,14 @@ namespace Orthanc
 
     static Encoding GetDefaultEncoding();
 
+    static void SetDefaultEncoding(Encoding encoding);
+
     static bool HasConfigurationChanged();
+
+    static void ExtractDicomSummary(DicomMap& target, 
+                                    DcmItem& dataset);
+
+    static void ExtractDicomAsJson(Json::Value& target, 
+                                   DcmDataset& dataset);
   };
 }
diff --git a/OrthancServer/OrthancMoveRequestHandler.cpp b/OrthancServer/OrthancMoveRequestHandler.cpp
index 240b703..b48f5a1 100644
--- a/OrthancServer/OrthancMoveRequestHandler.cpp
+++ b/OrthancServer/OrthancMoveRequestHandler.cpp
@@ -52,17 +52,20 @@ namespace Orthanc
       std::vector<std::string> instances_;
       size_t position_;
       RemoteModalityParameters remote_;
-      uint16_t moveRequestID_;
+      std::string originatorAet_;
+      uint16_t originatorId_;
 
     public:
       OrthancMoveRequestIterator(ServerContext& context,
                                  const std::string& aet,
                                  const std::string& publicId,
-                                 uint16_t moveRequestID) :
+                                 const std::string& originatorAet,
+                                 uint16_t originatorId) :
         context_(context),
         localAet_(context.GetDefaultLocalApplicationEntityTitle()),
         position_(0),
-        moveRequestID_(moveRequestID)
+        originatorAet_(originatorAet),
+        originatorId_(originatorId)
       {
         LOG(INFO) << "Sending resource " << publicId << " to modality \"" << aet << "\"";
 
@@ -93,12 +96,12 @@ namespace Orthanc
         const std::string& id = instances_[position_++];
 
         std::string dicom;
-        context_.ReadFile(dicom, id, FileContentType_Dicom);
+        context_.ReadDicom(dicom, id);
 
         {
           ReusableDicomUserConnection::Locker locker
             (context_.GetReusableDicomUserConnection(), localAet_, remote_);
-          locker.GetConnection().Store(dicom, moveRequestID_);
+          locker.GetConnection().Store(dicom, originatorAet_, originatorId_);
         }
 
         return Status_Success;
@@ -167,10 +170,10 @@ namespace Orthanc
 
   IMoveRequestIterator* OrthancMoveRequestHandler::Handle(const std::string& targetAet,
                                                           const DicomMap& input,
-                                                          const std::string& remoteIp,
-                                                          const std::string& remoteAet,
+                                                          const std::string& originatorIp,
+                                                          const std::string& originatorAet,
                                                           const std::string& calledAet,
-                                                          uint16_t messageId)
+                                                          uint16_t originatorId)
   {
     LOG(WARNING) << "Move-SCU request received for AET \"" << targetAet << "\"";
 
@@ -181,43 +184,13 @@ namespace Orthanc
         if (!query.GetElement(i).GetValue().IsNull())
         {
           LOG(INFO) << "  " << query.GetElement(i).GetTag()
-                    << "  " << FromDcmtkBridge::GetName(query.GetElement(i).GetTag())
+                    << "  " << FromDcmtkBridge::GetTagName(query.GetElement(i))
                     << " = " << query.GetElement(i).GetValue().GetContent();
         }
       }
     }
 
 
-#if 0
-    /**
-     * Retrieve the Message ID (0000,0110) for this C-MOVE request, if
-     * any. If present, this Message ID will be stored in the Move
-     * Originator Message ID (0000,1031) field of the C-MOVE response.
-     * http://dicom.nema.org/medical/dicom/current/output/html/part07.html#sect_9.3.1
-     **/
-
-    static const DicomTag MESSAGE_ID(0x0000, 0x0110);
-    const DicomValue* messageIdTmp = input.TestAndGetValue(MESSAGE_ID);
-
-    messageId = 0;
-
-    if (messageIdTmp != NULL &&
-        !messageIdTmp->IsNull() &&
-        !messageIdTmp->IsBinary())
-    {
-      try
-      {
-        messageId = boost::lexical_cast<uint16_t>(messageIdTmp->GetContent());
-      }
-      catch (boost::bad_lexical_cast&)
-      {
-        LOG(WARNING) << "Cannot convert the Message ID (\"" << messageIdTmp ->GetContent()
-                     << "\") of an incoming C-MOVE request to an integer, assuming zero";
-      }
-    }
-#endif
-
-
     /**
      * Retrieve the query level.
      **/
@@ -241,7 +214,7 @@ namespace Orthanc
           LookupIdentifier(publicId, ResourceType_Study, input) ||
           LookupIdentifier(publicId, ResourceType_Patient, input))
       {
-        return new OrthancMoveRequestIterator(context_, targetAet, publicId, messageId);
+        return new OrthancMoveRequestIterator(context_, targetAet, publicId, originatorAet, originatorId);
       }
       else
       {
@@ -262,7 +235,7 @@ namespace Orthanc
 
     if (LookupIdentifier(publicId, level, input))
     {
-      return new OrthancMoveRequestIterator(context_, targetAet, publicId, messageId);
+      return new OrthancMoveRequestIterator(context_, targetAet, publicId, originatorAet, originatorId);
     }
     else
     {
diff --git a/OrthancServer/OrthancMoveRequestHandler.h b/OrthancServer/OrthancMoveRequestHandler.h
index 18dc817..6d54eab 100644
--- a/OrthancServer/OrthancMoveRequestHandler.h
+++ b/OrthancServer/OrthancMoveRequestHandler.h
@@ -53,9 +53,9 @@ namespace Orthanc
 
     virtual IMoveRequestIterator* Handle(const std::string& targetAet,
                                          const DicomMap& input,
-                                         const std::string& remoteIp,
-                                         const std::string& remoteAet,
+                                         const std::string& originatorIp,
+                                         const std::string& originatorAet,
                                          const std::string& calledAet,
-                                         uint16_t messageId);
+                                         uint16_t originatorId);
   };
 }
diff --git a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
index 7168fbd..cb7f622 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
@@ -34,7 +34,6 @@
 #include "OrthancRestApi.h"
 
 #include "../../Core/Logging.h"
-#include "../../Core/Uuid.h"
 #include "../FromDcmtkBridge.h"
 #include "../ServerContext.h"
 #include "../OrthancInitialization.h"
@@ -137,6 +136,16 @@ namespace Orthanc
         ParseReplacements(target, request["Replace"]);
       }
 
+      // The "Keep" operation only makes sense for the tags
+      // StudyInstanceUID, SeriesInstanceUID and SOPInstanceUID. Avoid
+      // this feature as much as possible, as this breaks the DICOM
+      // model of the real world, except if you know exactly what
+      // you're doing!
+      if (request.isMember("Keep"))
+      {
+        ParseListOfTags(target, request["Keep"], TagOperation_Keep);
+      }
+
       return true;
     }
     else
@@ -674,7 +683,7 @@ namespace Orthanc
           throw OrthancException(ErrorCode_InternalError);
         }
 
-        context.ReadJson(siblingTags, siblingInstances.front());
+        context.ReadDicomAsJson(siblingTags, siblingInstances.front());
       }
 
 
@@ -758,7 +767,7 @@ namespace Orthanc
     
     // Inject time-related information
     std::string date, time;
-    Toolbox::GetNowDicom(date, time);
+    SystemToolbox::GetNowDicom(date, time);
     dicom.ReplacePlainString(DICOM_TAG_ACQUISITION_DATE, date);
     dicom.ReplacePlainString(DICOM_TAG_ACQUISITION_TIME, time);
     dicom.ReplacePlainString(DICOM_TAG_CONTENT_DATE, date);
diff --git a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp
index 66c2872..34ac44f 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp
@@ -38,7 +38,7 @@
 #include "../../Core/Compression/HierarchicalZipWriter.h"
 #include "../../Core/HttpServer/FilesystemHttpSender.h"
 #include "../../Core/Logging.h"
-#include "../../Core/Uuid.h"
+#include "../../Core/TemporaryFile.h"
 #include "../ServerContext.h"
 
 #include <stdio.h>
@@ -524,7 +524,7 @@ namespace Orthanc
                                const FileInfo& dicom)
       {
         std::string content;
-        context_.ReadFile(content, dicom);
+        context_.ReadAttachment(content, dicom);
 
         char filename[24];
         snprintf(filename, sizeof(filename) - 1, instanceFormat_, countInstances_);
@@ -547,7 +547,7 @@ namespace Orthanc
         const bool isZip64 = IsZip64Required(stats.GetUncompressedSize(), stats.GetInstancesCount());
 
         // Create a RAII for the temporary file to manage the ZIP file
-        Toolbox::TemporaryFile tmp;
+        TemporaryFile tmp;
 
         {
           // Create a ZIP writer
@@ -612,7 +612,7 @@ namespace Orthanc
         writer_.OpenFile(filename.c_str());
 
         std::string content;
-        context_.ReadFile(content, dicom);
+        context_.ReadAttachment(content, dicom);
         writer_.Write(content);
 
         ParsedDicomFile parsed(content);
@@ -634,7 +634,7 @@ namespace Orthanc
         const bool isZip64 = IsZip64Required(stats.GetUncompressedSize(), stats.GetInstancesCount());
 
         // Create a RAII for the temporary file to manage the ZIP file
-        Toolbox::TemporaryFile tmp;
+        TemporaryFile tmp;
 
         {
           // Create a ZIP writer
diff --git a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
index 3341a91..3f0ece0 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
@@ -178,7 +178,7 @@ namespace Orthanc
     RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
     ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
 
-    DicomFindAnswers answers;
+    DicomFindAnswers answers(false);
     FindPatient(answers, locker.GetConnection(), fields);
 
     Json::Value result;
@@ -208,7 +208,7 @@ namespace Orthanc
     RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
     ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
 
-    DicomFindAnswers answers;
+    DicomFindAnswers answers(false);
     FindStudy(answers, locker.GetConnection(), fields);
 
     Json::Value result;
@@ -239,7 +239,7 @@ namespace Orthanc
     RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
     ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
 
-    DicomFindAnswers answers;
+    DicomFindAnswers answers(false);
     FindSeries(answers, locker.GetConnection(), fields);
 
     Json::Value result;
@@ -271,7 +271,7 @@ namespace Orthanc
     RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
     ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
 
-    DicomFindAnswers answers;
+    DicomFindAnswers answers(false);
     FindInstance(answers, locker.GetConnection(), fields);
 
     Json::Value result;
@@ -308,7 +308,7 @@ namespace Orthanc
     RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
     ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
 
-    DicomFindAnswers patients;
+    DicomFindAnswers patients(false);
     FindPatient(patients, locker.GetConnection(), m);
 
     // Loop over the found patients
@@ -326,7 +326,7 @@ namespace Orthanc
 
       CopyTagIfExists(m, patients.GetAnswer(i), DICOM_TAG_PATIENT_ID);
 
-      DicomFindAnswers studies;
+      DicomFindAnswers studies(false);
       FindStudy(studies, locker.GetConnection(), m);
 
       patient["Studies"] = Json::arrayValue;
@@ -346,7 +346,7 @@ namespace Orthanc
         CopyTagIfExists(m, studies.GetAnswer(j), DICOM_TAG_PATIENT_ID);
         CopyTagIfExists(m, studies.GetAnswer(j), DICOM_TAG_STUDY_INSTANCE_UID);
 
-        DicomFindAnswers series;
+        DicomFindAnswers series(false);
         FindSeries(series, locker.GetConnection(), m);
 
         // Loop over the found series
@@ -683,58 +683,45 @@ namespace Orthanc
       return;
     }
 
-    static const char* LOCAL_AET = "LocalAet";
-    std::string localAet = context.GetDefaultLocalApplicationEntityTitle();
-    if (request.type() == Json::objectValue &&
-        request.isMember(LOCAL_AET))
-    {
-      if (request[LOCAL_AET].type() == Json::stringValue)
-      {
-        localAet = request[LOCAL_AET].asString();
-      }
-      else
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-    }
-
-    uint16_t moveOriginatorID = 0; /* By default, not a C-MOVE */
+    std::string localAet = Toolbox::GetJsonStringField(request, "LocalAet", context.GetDefaultLocalApplicationEntityTitle());
+    bool permissive = Toolbox::GetJsonBooleanField(request, "Permissive", false);
+    bool asynchronous = Toolbox::GetJsonBooleanField(request, "Asynchronous", false);
+    std::string moveOriginatorAET = Toolbox::GetJsonStringField(request, "MoveOriginatorAet", context.GetDefaultLocalApplicationEntityTitle());
+    int moveOriginatorID = Toolbox::GetJsonIntegerField(request, "MoveOriginatorID", 0 /* By default, not a C-MOVE */);
 
-    static const char* MOVE_ORIGINATOR_ID = "MoveOriginatorID";
-    if (request.type() == Json::objectValue &&
-        request.isMember(MOVE_ORIGINATOR_ID))
+    if (moveOriginatorID < 0 || 
+        moveOriginatorID >= 65536)
     {
-      if (request[MOVE_ORIGINATOR_ID].type() != Json::intValue)
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-
-      int v = request[MOVE_ORIGINATOR_ID].asInt();
-      if (v <= 0 || v >= 65536)
-      {
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-      }
-      else
-      {
-        moveOriginatorID = boost::lexical_cast<uint16_t>(v);
-      }
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
-
+    
     RemoteModalityParameters p = Configuration::GetModalityUsingSymbolicName(remote);
 
     ServerJob job;
     for (std::list<std::string>::const_iterator 
            it = instances.begin(); it != instances.end(); ++it)
     {
-      job.AddCommand(new StoreScuCommand(context, localAet, p, false,
-                                         moveOriginatorID)).AddInput(*it);
+      std::auto_ptr<StoreScuCommand> command(new StoreScuCommand(context, localAet, p, permissive));
+
+      if (moveOriginatorID != 0)
+      {
+        command->SetMoveOriginator(moveOriginatorAET, static_cast<uint16_t>(moveOriginatorID));
+      }
+
+      job.AddCommand(command.release()).AddInput(*it);
     }
 
     job.SetDescription("HTTP request: Store-SCU to peer \"" + remote + "\"");
 
-    if (context.GetScheduler().SubmitAndWait(job))
+    if (asynchronous)
     {
-      // Success
+      // Asynchronous mode: Submit the job, but don't wait for its completion
+      context.GetScheduler().Submit(job);
+      call.GetOutput().AnswerBuffer("{}", "application/json");
+    }
+    else if (context.GetScheduler().SubmitAndWait(job))
+    {
+      // Synchronous mode: We have submitted and waited for completion
       call.GetOutput().AnswerBuffer("{}", "application/json");
     }
     else
@@ -769,33 +756,8 @@ namespace Orthanc
 
     ResourceType level = StringToResourceType(request["Level"].asCString());
     
-    static const char* LOCAL_AET = "LocalAet";
-    std::string localAet = context.GetDefaultLocalApplicationEntityTitle();
-    if (request.isMember(LOCAL_AET))
-    {
-      if (request[LOCAL_AET].type() == Json::stringValue)
-      {
-        localAet = request[LOCAL_AET].asString();
-      }
-      else
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-    }
-
-    static const char* TARGET_AET = "TargetAet";
-    std::string targetAet = context.GetDefaultLocalApplicationEntityTitle();
-    if (request.isMember(TARGET_AET))
-    {
-      if (request[TARGET_AET].type() == Json::stringValue)
-      {
-        targetAet = request[TARGET_AET].asString();
-      }
-      else
-      {
-        throw OrthancException(ErrorCode_BadFileFormat);
-      }
-    }
+    std::string localAet = Toolbox::GetJsonStringField(request, "LocalAet", context.GetDefaultLocalApplicationEntityTitle());
+    std::string targetAet = Toolbox::GetJsonStringField(request, "TargetAet", context.GetDefaultLocalApplicationEntityTitle());
 
     const RemoteModalityParameters source = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
       
@@ -864,6 +826,8 @@ namespace Orthanc
       return;
     }
 
+    bool asynchronous = Toolbox::GetJsonBooleanField(request, "Asynchronous", false);
+
     WebServiceParameters peer;
     Configuration::GetOrthancPeer(peer, remote);
 
@@ -876,9 +840,15 @@ namespace Orthanc
 
     job.SetDescription("HTTP request: POST to peer \"" + remote + "\"");
 
-    if (context.GetScheduler().SubmitAndWait(job))
+    if (asynchronous)
+    {
+      // Asynchronous mode: Submit the job, but don't wait for its completion
+      context.GetScheduler().Submit(job);
+      call.GetOutput().AnswerBuffer("{}", "application/json");
+    }
+    else if (context.GetScheduler().SubmitAndWait(job))
     {
-      // Success
+      // Synchronous mode: We have submitted and waited for completion
       call.GetOutput().AnswerBuffer("{}", "application/json");
     }
     else
@@ -979,7 +949,7 @@ namespace Orthanc
 
       std::auto_ptr<ParsedDicomFile> query(ParsedDicomFile::CreateFromJson(json, static_cast<DicomFromJsonFlags>(0)));
 
-      DicomFindAnswers answers;
+      DicomFindAnswers answers(true);
 
       {
         ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
diff --git a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp
index dad9728..33c217f 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp
@@ -33,13 +33,15 @@
 #include "../PrecompiledHeadersServer.h"
 #include "OrthancRestApi.h"
 
-#include "../../Core/Logging.h"
 #include "../../Core/HttpServer/HttpContentNegociation.h"
-#include "../ServerToolbox.h"
+#include "../../Core/Logging.h"
 #include "../FromDcmtkBridge.h"
+#include "../Internals/DicomImageDecoder.h"
+#include "../OrthancInitialization.h"
+#include "../Search/LookupResource.h"
 #include "../ServerContext.h"
+#include "../ServerToolbox.h"
 #include "../SliceOrdering.h"
-#include "../Internals/DicomImageDecoder.h"
 
 
 namespace Orthanc
@@ -186,11 +188,11 @@ namespace Orthanc
     std::string publicId = call.GetUriComponent("id", "");
 
     std::string dicom;
-    context.ReadFile(dicom, publicId, FileContentType_Dicom);
+    context.ReadDicom(dicom, publicId);
 
     std::string target;
     call.BodyToString(target);
-    Toolbox::WriteFile(dicom, target);
+    SystemToolbox::WriteFile(dicom, target);
 
     call.GetOutput().AnswerBuffer("{}", "application/json");
   }
@@ -206,15 +208,17 @@ namespace Orthanc
     if (simplify)
     {
       Json::Value full;
-      context.ReadJson(full, publicId);
+      context.ReadDicomAsJson(full, publicId);
 
       Json::Value simplified;
-      Toolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Human);
+      ServerToolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Human);
       call.GetOutput().AnswerJson(simplified);
     }
     else
     {
-      context.AnswerAttachment(call.GetOutput(), publicId, FileContentType_DicomAsJson);
+      std::string full;
+      context.ReadDicomAsJson(full, publicId);
+      call.GetOutput().AnswerBuffer(full, "application/json");
     }
   }
 
@@ -374,12 +378,12 @@ namespace Orthanc
     {
       std::string publicId = call.GetUriComponent("id", "");
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
       if (context.GetPlugins().HasCustomImageDecoder())
       {
         // TODO create a cache of file
         std::string dicomContent;
-        context.ReadFile(dicomContent, publicId, FileContentType_Dicom);
+        context.ReadDicom(dicomContent, publicId);
         decoded.reset(context.GetPlugins().DecodeUnsafe(dicomContent.c_str(), dicomContent.size(), frame));
 
         /**
@@ -449,9 +453,9 @@ namespace Orthanc
 
     std::string publicId = call.GetUriComponent("id", "");
     std::string dicomContent;
-    context.ReadFile(dicomContent, publicId, FileContentType_Dicom);
+    context.ReadDicom(dicomContent, publicId);
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
     IDicomImageDecoder& decoder = context.GetPlugins();
 #else
     DefaultDicomImageDecoder decoder;  // This is Orthanc's built-in decoder
@@ -562,6 +566,10 @@ namespace Orthanc
       OrthancRestApi::GetIndex(call).DeleteMetadata(publicId, metadata);
       call.GetOutput().AnswerBuffer("", "text/plain");
     }
+    else
+    {
+      call.GetOutput().SignalError(HttpStatus_403_Forbidden);
+    }
   }
 
 
@@ -582,6 +590,10 @@ namespace Orthanc
       OrthancRestApi::GetIndex(call).SetMetadata(publicId, metadata, value);
       call.GetOutput().AnswerBuffer("", "text/plain");
     }
+    else
+    {
+      call.GetOutput().SignalError(HttpStatus_403_Forbidden);
+    }
   }
 
 
@@ -676,7 +688,7 @@ namespace Orthanc
     {
       // Return the raw data (possibly compressed), as stored on the filesystem
       std::string content;
-      context.ReadFile(content, publicId, type, false);
+      context.ReadAttachment(content, publicId, type, false);
       call.GetOutput().AnswerBuffer(content, "application/octet-stream");
     }
   }
@@ -745,7 +757,7 @@ namespace Orthanc
 
     // First check whether the compressed data is correctly stored in the disk
     std::string data;
-    context.ReadFile(data, publicId, StringToContentType(name), false);
+    context.ReadAttachment(data, publicId, StringToContentType(name), false);
 
     std::string actualMD5;
     Toolbox::ComputeMD5(actualMD5, data);
@@ -760,7 +772,7 @@ namespace Orthanc
       }
       else
       {
-        context.ReadFile(data, publicId, StringToContentType(name), true);        
+        context.ReadAttachment(data, publicId, StringToContentType(name), true);        
         Toolbox::ComputeMD5(actualMD5, data);
         ok = (actualMD5 == info.GetUncompressedMD5());
       }
@@ -792,6 +804,10 @@ namespace Orthanc
     {
       call.GetOutput().AnswerBuffer("{}", "application/json");
     }
+    else
+    {
+      call.GetOutput().SignalError(HttpStatus_403_Forbidden);
+    }
   }
 
 
@@ -803,11 +819,33 @@ namespace Orthanc
     std::string name = call.GetUriComponent("name", "");
     FileContentType contentType = StringToContentType(name);
 
-    if (IsUserContentType(contentType))  // It is forbidden to delete internal attachments
+    bool allowed;
+    if (IsUserContentType(contentType))
+    {
+      allowed = true;
+    }
+    else if (Configuration::GetGlobalBoolParameter("StoreDicom", true) &&
+             contentType == FileContentType_DicomAsJson)
+    {
+      allowed = true;
+    }
+    else
+    {
+      // It is forbidden to delete internal attachments, except for
+      // the "DICOM as JSON" summary as of Orthanc 1.2.0 (this summary
+      // would be automatically reconstructed on the next GET call)
+      allowed = false;
+    }
+
+    if (allowed) 
     {
       OrthancRestApi::GetIndex(call).DeleteAttachment(publicId, contentType);
       call.GetOutput().AnswerBuffer("{}", "application/json");
     }
+    else
+    {
+      call.GetOutput().SignalError(HttpStatus_403_Forbidden);
+    }
   }
 
 
@@ -870,7 +908,7 @@ namespace Orthanc
 
       try
       {
-        context.ReadJson(tags, *it);
+        context.ReadDicomAsJson(tags, *it);
       }
       catch (OrthancException&)
       {
@@ -937,7 +975,7 @@ namespace Orthanc
       if (simplify)
       {
         Json::Value simplified;
-        Toolbox::SimplifyTags(simplified, sharedTags, DicomToJsonFormat_Human);
+        ServerToolbox::SimplifyTags(simplified, sharedTags, DicomToJsonFormat_Human);
         call.GetOutput().AnswerJson(simplified);
       }
       else
@@ -988,7 +1026,7 @@ namespace Orthanc
       publicId = instances.front();
     }
 
-    context.ReadJson(tags, publicId);
+    context.ReadDicomAsJson(tags, publicId);
     
     // Filter the tags of the instance according to the module
     Json::Value result = Json::objectValue;
@@ -1004,7 +1042,7 @@ namespace Orthanc
     if (simplify)
     {
       Json::Value simplified;
-      Toolbox::SimplifyTags(simplified, result, DicomToJsonFormat_Human);
+      ServerToolbox::SimplifyTags(simplified, result, DicomToJsonFormat_Human);
       call.GetOutput().AnswerJson(simplified);
     }
     else
@@ -1205,12 +1243,12 @@ namespace Orthanc
          it != instances.end(); ++it)
     {
       Json::Value full;
-      context.ReadJson(full, *it);
+      context.ReadDicomAsJson(full, *it);
 
       if (simplify)
       {
         Json::Value simplified;
-        Toolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Human);
+        ServerToolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Human);
         result[*it] = simplified;
       }
       else
@@ -1294,7 +1332,7 @@ namespace Orthanc
     bool simplify = call.HasArgument("simplify");
 
     std::string dicomContent;
-    context.ReadFile(dicomContent, publicId, FileContentType_Dicom);
+    context.ReadDicom(dicomContent, publicId);
 
     // TODO Consider using "DicomMap::ParseDicomMetaInformation()" to
     // speed up things here
@@ -1307,7 +1345,7 @@ namespace Orthanc
     if (simplify)
     {
       Json::Value simplified;
-      Toolbox::SimplifyTags(simplified, header, DicomToJsonFormat_Human);
+      ServerToolbox::SimplifyTags(simplified, header, DicomToJsonFormat_Human);
       call.GetOutput().AnswerJson(simplified);
     }
     else
@@ -1317,6 +1355,41 @@ namespace Orthanc
   }
 
 
+  static void InvalidateTags(RestApiPostCall& call)
+  {
+    ServerIndex& index = OrthancRestApi::GetIndex(call);
+    
+    // Loop over the instances, grouping them by parent studies so as
+    // to avoid large memory consumption
+    std::list<std::string> studies;
+    index.GetAllUuids(studies, ResourceType_Study);
+
+    for (std::list<std::string>::const_iterator 
+           study = studies.begin(); study != studies.end(); ++study)
+    {
+      std::list<std::string> instances;
+      index.GetChildInstances(instances, *study);
+
+      for (std::list<std::string>::const_iterator 
+             instance = instances.begin(); instance != instances.end(); ++instance)
+      {
+        index.DeleteAttachment(*instance, FileContentType_DicomAsJson);
+      }
+    }
+
+    call.GetOutput().AnswerBuffer("", "text/plain");
+  }
+
+
+  template <enum ResourceType type>
+  static void ReconstructResource(RestApiPostCall& call)
+  {
+    ServerContext& context = OrthancRestApi::GetContext(call);
+    ServerToolbox::ReconstructResource(context, call.GetUriComponent("id", ""));
+    call.GetOutput().AnswerBuffer("", "text/plain");
+  }
+
+
   void OrthancRestApi::RegisterResources()
   {
     Register("/instances", ListResources<ResourceType_Instance>);
@@ -1391,6 +1464,7 @@ namespace Orthanc
     Register("/{resourceType}/{id}/attachments/{name}/uncompress", ChangeAttachmentCompression<CompressionType_None>);
     Register("/{resourceType}/{id}/attachments/{name}/verify-md5", VerifyAttachment);
 
+    Register("/tools/invalidate-tags", InvalidateTags);
     Register("/tools/lookup", Lookup);
     Register("/tools/find", Find);
 
@@ -1415,5 +1489,10 @@ namespace Orthanc
     Register("/instances/{id}/content/*", GetRawContent);
 
     Register("/series/{id}/ordered-slices", OrderSlices);
+
+    Register("/patients/{id}/reconstruct", ReconstructResource<ResourceType_Patient>);
+    Register("/studies/{id}/reconstruct", ReconstructResource<ResourceType_Study>);
+    Register("/series/{id}/reconstruct", ReconstructResource<ResourceType_Series>);
+    Register("/instances/{id}/reconstruct", ReconstructResource<ResourceType_Instance>);
   }
 }
diff --git a/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp b/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp
index 7678674..f86cd73 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp
@@ -55,15 +55,15 @@ namespace Orthanc
 
     result["DatabaseVersion"] = OrthancRestApi::GetIndex(call).GetDatabaseVersion();
     result["DicomAet"] = Configuration::GetGlobalStringParameter("DicomAet", "ORTHANC");
-    result["DicomPort"] = Configuration::GetGlobalIntegerParameter("DicomPort", 4242);
-    result["HttpPort"] = Configuration::GetGlobalIntegerParameter("HttpPort", 8042);
+    result["DicomPort"] = Configuration::GetGlobalUnsignedIntegerParameter("DicomPort", 4242);
+    result["HttpPort"] = Configuration::GetGlobalUnsignedIntegerParameter("HttpPort", 8042);
     result["Name"] = Configuration::GetGlobalStringParameter("Name", "");
     result["Version"] = ORTHANC_VERSION;
 
     result["StorageAreaPlugin"] = Json::nullValue;
     result["DatabaseBackendPlugin"] = Json::nullValue;
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
     result["PluginsEnabled"] = true;
     const OrthancPlugins& plugins = OrthancRestApi::GetContext(call).GetPlugins();
 
@@ -131,7 +131,7 @@ namespace Orthanc
 
   static void GetNowIsoString(RestApiGetCall& call)
   {
-    call.GetOutput().AnswerBuffer(Toolbox::GetNowIsoString(), "text/plain");
+    call.GetOutput().AnswerBuffer(SystemToolbox::GetNowIsoString(), "text/plain");
   }
 
 
@@ -153,7 +153,7 @@ namespace Orthanc
 
     if (OrthancRestApi::GetContext(call).HasPlugins())
     {
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
       std::list<std::string> plugins;
       OrthancRestApi::GetContext(call).GetPlugins().GetManager().ListPlugins(plugins);
 
@@ -176,7 +176,7 @@ namespace Orthanc
       return;
     }
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
     const PluginsManager& manager = OrthancRestApi::GetContext(call).GetPlugins().GetManager();
     std::string id = call.GetUriComponent("id", "");
 
@@ -224,7 +224,7 @@ namespace Orthanc
 
     if (OrthancRestApi::GetContext(call).HasPlugins())
     {
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
       const OrthancPlugins& plugins = OrthancRestApi::GetContext(call).GetPlugins();
       const PluginsManager& manager = plugins.GetManager();
 
@@ -248,6 +248,23 @@ namespace Orthanc
   }
 
 
+  static void GetDefaultEncoding(RestApiGetCall& call)
+  {
+    Encoding encoding = Configuration::GetDefaultEncoding();
+    call.GetOutput().AnswerBuffer(EnumerationToString(encoding), "text/plain");
+  }
+
+
+  static void SetDefaultEncoding(RestApiPutCall& call)
+  {
+    Encoding encoding = StringToEncoding(call.GetBodyData());
+
+    Configuration::SetDefaultEncoding(encoding);
+
+    call.GetOutput().AnswerBuffer(EnumerationToString(encoding), "text/plain");
+  }
+
+
   void OrthancRestApi::RegisterSystem()
   {
     Register("/", ServeRoot);
@@ -257,6 +274,8 @@ namespace Orthanc
     Register("/tools/execute-script", ExecuteScript);
     Register("/tools/now", GetNowIsoString);
     Register("/tools/dicom-conformance", GetDicomConformanceStatement);
+    Register("/tools/default-encoding", GetDefaultEncoding);
+    Register("/tools/default-encoding", SetDefaultEncoding);
 
     Register("/plugins", ListPlugins);
     Register("/plugins/{id}", GetPlugin);
diff --git a/OrthancServer/ParsedDicomFile.cpp b/OrthancServer/ParsedDicomFile.cpp
index 27b84f5..bc5ecf0 100644
--- a/OrthancServer/ParsedDicomFile.cpp
+++ b/OrthancServer/ParsedDicomFile.cpp
@@ -90,7 +90,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../Core/Logging.h"
 #include "../Core/OrthancException.h"
 #include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
 
 #include <list>
 #include <limits>
@@ -855,7 +854,7 @@ namespace Orthanc
     // TODO Avoid using a temporary memory buffer, write directly on disk
     std::string content;
     SaveToMemoryBuffer(content);
-    Toolbox::WriteFile(content, path);
+    SystemToolbox::WriteFile(content, path);
   }
 
 
@@ -873,15 +872,55 @@ namespace Orthanc
   }
 
 
-  ParsedDicomFile::ParsedDicomFile(const DicomMap& map) : pimpl_(new PImpl)
+  void ParsedDicomFile::CreateFromDicomMap(const DicomMap& source,
+                                           Encoding defaultEncoding)
   {
-    std::auto_ptr<DcmDataset> dataset(ToDcmtkBridge::Convert(map));
+    pimpl_->file_.reset(new DcmFileFormat);
+
+    const DicomValue* tmp = source.TestAndGetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET);
+    if (tmp != NULL)
+    {
+      Encoding encoding;
+      if (tmp->IsNull() ||
+          tmp->IsBinary() ||
+          !GetDicomEncoding(encoding, tmp->GetContent().c_str()))
+      {
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+      else
+      {
+        SetEncoding(encoding);
+      }
+    }
+    else
+    {
+      SetEncoding(defaultEncoding);
+    }
+
+    for (DicomMap::Map::const_iterator 
+           it = source.map_.begin(); it != source.map_.end(); ++it)
+    {
+      if (it->first != DICOM_TAG_SPECIFIC_CHARACTER_SET &&
+          !it->second->IsNull())
+      {
+        ReplacePlainString(it->first, it->second->GetContent());
+      }
+    }
+  }
 
-    // NOTE: This implies an unnecessary memory copy of the dataset, but no way to get around
-    // http://support.dcmtk.org/redmine/issues/544
-    std::auto_ptr<DcmFileFormat> fileFormat(new DcmFileFormat(dataset.get()));
 
-    pimpl_->file_.reset(fileFormat.release());
+  ParsedDicomFile::ParsedDicomFile(const DicomMap& map,
+                                   Encoding defaultEncoding) :
+    pimpl_(new PImpl)
+  {
+    CreateFromDicomMap(map, defaultEncoding);
+  }
+
+
+  ParsedDicomFile::ParsedDicomFile(const DicomMap& map) : 
+    pimpl_(new PImpl)
+  {
+    CreateFromDicomMap(map, Configuration::GetDefaultEncoding());
   }
 
 
@@ -1146,21 +1185,26 @@ namespace Orthanc
     ReplacePlainString(DICOM_TAG_SPECIFIC_CHARACTER_SET, s);
   }
 
-  void ParsedDicomFile::ToJson(Json::Value& target, 
-                               DicomToJsonFormat format,
-                               DicomToJsonFlags flags,
-                               unsigned int maxStringLength)
+  void ParsedDicomFile::DatasetToJson(Json::Value& target, 
+                                      DicomToJsonFormat format,
+                                      DicomToJsonFlags flags,
+                                      unsigned int maxStringLength)
+  {
+    FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset(),
+                                        format, flags, maxStringLength, Configuration::GetDefaultEncoding());
+  }
+
+
+  void ParsedDicomFile::DatasetToJson(Json::Value& target)
   {
-    FromDcmtkBridge::ToJson(target, *pimpl_->file_->getDataset(),
-                            format, flags, maxStringLength,
-                            Configuration::GetDefaultEncoding());
+    Configuration::ExtractDicomAsJson(target, *pimpl_->file_->getDataset());
   }
 
 
   void ParsedDicomFile::HeaderToJson(Json::Value& target, 
                                      DicomToJsonFormat format)
   {
-    FromDcmtkBridge::ToJson(target, *pimpl_->file_->getMetaInfo(), format, DicomToJsonFlags_None, 0);
+    FromDcmtkBridge::ExtractHeaderAsJson(target, *pimpl_->file_->getMetaInfo(), format, DicomToJsonFlags_None, 0);
   }
 
 
@@ -1256,14 +1300,6 @@ namespace Orthanc
   }
 
 
-  void ParsedDicomFile::Convert(DicomMap& tags)
-  {
-    FromDcmtkBridge::Convert(tags, *pimpl_->file_->getDataset(), 
-                             ORTHANC_MAXIMUM_TAG_LENGTH, 
-                             Configuration::GetDefaultEncoding());
-  }
-
-
   ParsedDicomFile* ParsedDicomFile::CreateFromJson(const Json::Value& json,
                                                    DicomFromJsonFlags flags)
   {
@@ -1342,4 +1378,34 @@ namespace Orthanc
   {
     return DicomFrameIndex::GetFramesCount(*pimpl_->file_);
   }
+
+
+  void ParsedDicomFile::ChangeEncoding(Encoding target)
+  {
+    Encoding source = GetEncoding();
+
+    if (source != target)  // Avoid unnecessary conversion
+    {
+      ReplacePlainString(DICOM_TAG_SPECIFIC_CHARACTER_SET, GetDicomSpecificCharacterSet(target));
+      FromDcmtkBridge::ChangeStringEncoding(*pimpl_->file_->getDataset(), source, target);
+    }
+  }
+
+
+  void ParsedDicomFile::ExtractDicomSummary(DicomMap& target) const
+  {
+    Configuration::ExtractDicomSummary(target, *pimpl_->file_->getDataset());
+  }
+
+
+  void ParsedDicomFile::ExtractDicomAsJson(Json::Value& target) const
+  {
+    Configuration::ExtractDicomAsJson(target, *pimpl_->file_->getDataset());
+  }
+
+
+  bool ParsedDicomFile::LookupTransferSyntax(std::string& result)
+  {
+    return FromDcmtkBridge::LookupTransferSyntax(result, *pimpl_->file_);
+  }
 }
diff --git a/OrthancServer/ParsedDicomFile.h b/OrthancServer/ParsedDicomFile.h
index 011ff75..b5f7930 100644
--- a/OrthancServer/ParsedDicomFile.h
+++ b/OrthancServer/ParsedDicomFile.h
@@ -36,6 +36,7 @@
 #include "../Core/Images/ImageAccessor.h"
 #include "../Core/IDynamicObject.h"
 #include "../Core/RestApi/RestApiOutput.h"
+#include "../Core/Toolbox.h"
 #include "ServerEnumerations.h"
 
 class DcmDataset;
@@ -51,6 +52,9 @@ namespace Orthanc
 
     ParsedDicomFile(ParsedDicomFile& other);
 
+    void CreateFromDicomMap(const DicomMap& source,
+                            Encoding defaultEncoding);
+
     void RemovePrivateTagsInternal(const std::set<DicomTag>* toKeep);
 
     void UpdateStorageUid(const DicomTag& tag,
@@ -64,6 +68,9 @@ namespace Orthanc
   public:
     ParsedDicomFile(bool createIdentifiers);  // Create a minimal DICOM instance
 
+    ParsedDicomFile(const DicomMap& map,
+                    Encoding defaultEncoding);
+
     ParsedDicomFile(const DicomMap& map);
 
     ParsedDicomFile(const void* content,
@@ -118,6 +125,7 @@ namespace Orthanc
       RemovePrivateTagsInternal(&toKeep);
     }
 
+    // WARNING: This function handles the decoding of strings to UTF8
     bool GetTagValue(std::string& value,
                      const DicomTag& tag);
 
@@ -136,12 +144,18 @@ namespace Orthanc
 
     Encoding GetEncoding() const;
 
+    // WARNING: This function only sets the encoding, it will not
+    // convert the encoding of the tags. Use "ChangeEncoding()" if need be.
     void SetEncoding(Encoding encoding);
 
-    void ToJson(Json::Value& target, 
-                DicomToJsonFormat format,
-                DicomToJsonFlags flags,
-                unsigned int maxStringLength);
+    void DatasetToJson(Json::Value& target, 
+                       DicomToJsonFormat format,
+                       DicomToJsonFlags flags,
+                       unsigned int maxStringLength);
+
+    // This version uses the default parameters for
+    // FileContentType_DicomAsJson
+    void DatasetToJson(Json::Value& target);
 
     void HeaderToJson(Json::Value& target, 
                       DicomToJsonFormat format);
@@ -152,8 +166,6 @@ namespace Orthanc
 
     bool ExtractPdf(std::string& pdf);
 
-    void Convert(DicomMap& tags);
-
     void GetRawFrame(std::string& target, // OUT
                      std::string& mime,   // OUT
                      unsigned int frameId);  // IN
@@ -162,6 +174,13 @@ namespace Orthanc
 
     static ParsedDicomFile* CreateFromJson(const Json::Value& value,
                                            DicomFromJsonFlags flags);
-  };
 
+    void ChangeEncoding(Encoding target);
+
+    void ExtractDicomSummary(DicomMap& target) const;
+
+    void ExtractDicomAsJson(Json::Value& target) const;
+
+    bool LookupTransferSyntax(std::string& result);
+  };
 }
diff --git a/OrthancServer/QueryRetrieveHandler.cpp b/OrthancServer/QueryRetrieveHandler.cpp
index 3effdda..595d165 100644
--- a/OrthancServer/QueryRetrieveHandler.cpp
+++ b/OrthancServer/QueryRetrieveHandler.cpp
@@ -34,10 +34,43 @@
 #include "QueryRetrieveHandler.h"
 
 #include "OrthancInitialization.h"
+#include "FromDcmtkBridge.h"
 
 
 namespace Orthanc
 {
+  static void FixQuery(DicomMap& query,
+                       ServerContext& context,
+                       const std::string& modality)
+  {
+    static const char* LUA_CALLBACK = "OutgoingFindRequestFilter";
+
+    LuaScripting::Locker locker(context.GetLua());
+    if (locker.GetLua().IsExistingFunction(LUA_CALLBACK))
+    {
+      LuaFunctionCall call(locker.GetLua(), LUA_CALLBACK);
+      call.PushDicom(query);
+      call.PushJson(modality);
+      FromDcmtkBridge::ExecuteToDicom(query, call);
+    }
+  }
+
+
+  static void FixQuery(DicomMap& query,
+                       ModalityManufacturer manufacturer)
+  {
+    /**
+     * Introduce patches for specific manufacturers below.
+     **/
+
+    switch (manufacturer)
+    {
+      default:
+        break;
+    }
+  }
+
+
   void QueryRetrieveHandler::Invalidate()
   {
     done_ = false;
@@ -49,8 +82,20 @@ namespace Orthanc
   {
     if (!done_)
     {
-      ReusableDicomUserConnection::Locker locker(context_.GetReusableDicomUserConnection(), localAet_, modality_);
-      locker.GetConnection().Find(answers_, level_, query_);
+      // Firstly, fix the content of the query for specific manufacturers
+      DicomMap fixed;
+      fixed.Assign(query_);
+      FixQuery(fixed, modality_.GetManufacturer());
+
+      // Secondly, possibly fix the query with the user-provider Lua callback
+      FixQuery(fixed, context_, modality_.GetApplicationEntityTitle()); 
+
+      {
+        // Finally, run the C-FIND SCU against the fixed query
+        ReusableDicomUserConnection::Locker locker(context_.GetReusableDicomUserConnection(), localAet_, modality_);
+        locker.GetConnection().Find(answers_, level_, fixed);
+      }
+
       done_ = true;
     }
   }
@@ -60,7 +105,8 @@ namespace Orthanc
     context_(context),
     localAet_(context.GetDefaultLocalApplicationEntityTitle()),
     done_(false),
-    level_(ResourceType_Study)
+    level_(ResourceType_Study),
+    answers_(false)
   {
   }
 
@@ -99,7 +145,7 @@ namespace Orthanc
                                        size_t i)
   {
     Run();
-    answers_.GetAnswer(i).Convert(target);
+    answers_.GetAnswer(i).ExtractDicomSummary(target);
   }
 
 
diff --git a/OrthancServer/Scheduler/CallSystemCommand.cpp b/OrthancServer/Scheduler/CallSystemCommand.cpp
index 135a788..751dc9b 100644
--- a/OrthancServer/Scheduler/CallSystemCommand.cpp
+++ b/OrthancServer/Scheduler/CallSystemCommand.cpp
@@ -35,7 +35,7 @@
 
 #include "../../Core/Logging.h"
 #include "../../Core/Toolbox.h"
-#include "../../Core/Uuid.h"
+#include "../../Core/TemporaryFile.h"
 
 namespace Orthanc
 {
@@ -59,15 +59,15 @@ namespace Orthanc
       try
       {
         std::string dicom;
-        context_.ReadFile(dicom, *it, FileContentType_Dicom);
+        context_.ReadDicom(dicom, *it);
 
-        Toolbox::TemporaryFile tmp;
+        TemporaryFile tmp;
         tmp.Write(dicom);
 
         std::vector<std::string> args = arguments_;
         args.push_back(tmp.GetPath());
 
-        Toolbox::ExecuteSystemCommand(command_, args);
+        SystemToolbox::ExecuteSystemCommand(command_, args);
 
         // Only chain with other commands if this command succeeds
         outputs.push_back(*it);
diff --git a/OrthancServer/Scheduler/ServerJob.cpp b/OrthancServer/Scheduler/ServerJob.cpp
index c5ec396..a43ee1e 100644
--- a/OrthancServer/Scheduler/ServerJob.cpp
+++ b/OrthancServer/Scheduler/ServerJob.cpp
@@ -34,8 +34,8 @@
 #include "ServerJob.h"
 
 #include "../../Core/OrthancException.h"
+#include "../../Core/SystemToolbox.h"
 #include "../../Core/Toolbox.h"
-#include "../../Core/Uuid.h"
 
 namespace Orthanc
 {
@@ -96,7 +96,7 @@ namespace Orthanc
 
 
   ServerJob::ServerJob() :
-    jobId_(Toolbox::GenerateUuid()),
+    jobId_(SystemToolbox::GenerateUuid()),
     submitted_(false),
     description_("no description")
   {
diff --git a/OrthancServer/Scheduler/ServerScheduler.cpp b/OrthancServer/Scheduler/ServerScheduler.cpp
index 45831a3..dfe4b2c 100644
--- a/OrthancServer/Scheduler/ServerScheduler.cpp
+++ b/OrthancServer/Scheduler/ServerScheduler.cpp
@@ -47,7 +47,7 @@ namespace Orthanc
       ListOfStrings& target_;
 
     public:
-      Sink(ListOfStrings& target) : target_(target)
+      explicit Sink(ListOfStrings& target) : target_(target)
       {
       }
 
@@ -192,6 +192,11 @@ namespace Orthanc
 
   ServerScheduler::ServerScheduler(unsigned int maxJobs) : availableJob_(maxJobs)
   {
+    if (maxJobs == 0)
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
     finish_ = false;
     worker_ = boost::thread(Worker, this);
   }
diff --git a/OrthancServer/Scheduler/ServerScheduler.h b/OrthancServer/Scheduler/ServerScheduler.h
index 341f829..0da65ff 100644
--- a/OrthancServer/Scheduler/ServerScheduler.h
+++ b/OrthancServer/Scheduler/ServerScheduler.h
@@ -82,7 +82,7 @@ namespace Orthanc
                         bool watched);
 
   public:
-    ServerScheduler(unsigned int maxjobs);
+    explicit ServerScheduler(unsigned int maxjobs);
 
     ~ServerScheduler();
 
diff --git a/OrthancServer/Scheduler/StorePeerCommand.cpp b/OrthancServer/Scheduler/StorePeerCommand.cpp
index ab9f677..8acbbb3 100644
--- a/OrthancServer/Scheduler/StorePeerCommand.cpp
+++ b/OrthancServer/Scheduler/StorePeerCommand.cpp
@@ -62,7 +62,7 @@ namespace Orthanc
 
       try
       {
-        context_.ReadFile(client.GetBody(), *it, FileContentType_Dicom);
+        context_.ReadDicom(client.GetBody(), *it);
 
         std::string answer;
         if (!client.Apply(answer))
diff --git a/OrthancServer/Scheduler/StoreScuCommand.cpp b/OrthancServer/Scheduler/StoreScuCommand.cpp
index 7404064..c698b2d 100644
--- a/OrthancServer/Scheduler/StoreScuCommand.cpp
+++ b/OrthancServer/Scheduler/StoreScuCommand.cpp
@@ -40,16 +40,24 @@ namespace Orthanc
   StoreScuCommand::StoreScuCommand(ServerContext& context,
                                    const std::string& localAet,
                                    const RemoteModalityParameters& modality,
-                                   bool ignoreExceptions,
-                                   uint16_t moveOriginatorID) : 
+                                   bool ignoreExceptions) : 
     context_(context),
     modality_(modality),
     ignoreExceptions_(ignoreExceptions),
     localAet_(localAet),
-    moveOriginatorID_(moveOriginatorID)
+    moveOriginatorID_(0)
   {
   }
 
+
+  void StoreScuCommand::SetMoveOriginator(const std::string& aet,
+                                          uint16_t id)
+  {
+    moveOriginatorAET_ = aet;
+    moveOriginatorID_ = id;
+  }
+
+
   bool StoreScuCommand::Apply(ListOfStrings& outputs,
                              const ListOfStrings& inputs)
   {
@@ -64,9 +72,9 @@ namespace Orthanc
       try
       {
         std::string dicom;
-        context_.ReadFile(dicom, *it, FileContentType_Dicom);
+        context_.ReadDicom(dicom, *it);
 
-        locker.GetConnection().Store(dicom, moveOriginatorID_);
+        locker.GetConnection().Store(dicom, moveOriginatorAET_, moveOriginatorID_);
 
         // Only chain with other commands if this command succeeds
         outputs.push_back(*it);
diff --git a/OrthancServer/Scheduler/StoreScuCommand.h b/OrthancServer/Scheduler/StoreScuCommand.h
index 1070c35..b1ead73 100644
--- a/OrthancServer/Scheduler/StoreScuCommand.h
+++ b/OrthancServer/Scheduler/StoreScuCommand.h
@@ -44,15 +44,17 @@ namespace Orthanc
     RemoteModalityParameters modality_;
     bool ignoreExceptions_;
     std::string localAet_;
+    std::string moveOriginatorAET_;
     uint16_t moveOriginatorID_;
 
   public:
     StoreScuCommand(ServerContext& context,
                     const std::string& localAet,
                     const RemoteModalityParameters& modality,
-                    bool ignoreExceptions,
-                    uint16_t moveOriginatorID /* only makes sense if this 
-                                                 command results from a C-MOVE */);
+                    bool ignoreExceptions);
+
+    void SetMoveOriginator(const std::string& aet,
+                           uint16_t id);
 
     virtual bool Apply(ListOfStrings& outputs,
                        const ListOfStrings& inputs);
diff --git a/OrthancServer/Search/HierarchicalMatcher.cpp b/OrthancServer/Search/HierarchicalMatcher.cpp
index daefa4c..9e71a03 100644
--- a/OrthancServer/Search/HierarchicalMatcher.cpp
+++ b/OrthancServer/Search/HierarchicalMatcher.cpp
@@ -86,9 +86,9 @@ namespace Orthanc
       }
 
       DicomTag tag(FromDcmtkBridge::Convert(element->getTag()));
-      if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET)
+      if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET ||   // Ignore encoding
+          tag.GetElement() == 0x0000)  // Ignore all "Group Length" tags
       {
-        // Ignore this specific tag
         continue;
       }
 
diff --git a/OrthancServer/Search/LookupIdentifierQuery.cpp b/OrthancServer/Search/LookupIdentifierQuery.cpp
index b56f95f..7b4c3f5 100644
--- a/OrthancServer/Search/LookupIdentifierQuery.cpp
+++ b/OrthancServer/Search/LookupIdentifierQuery.cpp
@@ -43,67 +43,6 @@
 
 namespace Orthanc
 {
-  static const DicomTag patientIdentifiers[] = 
-  {
-    DICOM_TAG_PATIENT_ID,
-    DICOM_TAG_PATIENT_NAME,
-    DICOM_TAG_PATIENT_BIRTH_DATE
-  };
-
-  static const DicomTag studyIdentifiers[] = 
-  {
-    DICOM_TAG_PATIENT_ID,
-    DICOM_TAG_PATIENT_NAME,
-    DICOM_TAG_PATIENT_BIRTH_DATE,
-    DICOM_TAG_STUDY_INSTANCE_UID,
-    DICOM_TAG_ACCESSION_NUMBER,
-    DICOM_TAG_STUDY_DESCRIPTION,
-    DICOM_TAG_STUDY_DATE
-  };
-
-  static const DicomTag seriesIdentifiers[] = 
-  {
-    DICOM_TAG_SERIES_INSTANCE_UID
-  };
-
-  static const DicomTag instanceIdentifiers[] = 
-  {
-    DICOM_TAG_SOP_INSTANCE_UID
-  };
-
-
-  void LookupIdentifierQuery::LoadIdentifiers(const DicomTag*& tags,
-                                              size_t& size,
-                                              ResourceType level)
-  {
-    switch (level)
-    {
-      case ResourceType_Patient:
-        tags = patientIdentifiers;
-        size = sizeof(patientIdentifiers) / sizeof(DicomTag);
-        break;
-
-      case ResourceType_Study:
-        tags = studyIdentifiers;
-        size = sizeof(studyIdentifiers) / sizeof(DicomTag);
-        break;
-
-      case ResourceType_Series:
-        tags = seriesIdentifiers;
-        size = sizeof(seriesIdentifiers) / sizeof(DicomTag);
-        break;
-
-      case ResourceType_Instance:
-        tags = instanceIdentifiers;
-        size = sizeof(instanceIdentifiers) / sizeof(DicomTag);
-        break;
-
-      default:
-        throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-  }
-
-
   LookupIdentifierQuery::Disjunction::~Disjunction()
   {
     for (size_t i = 0; i < disjunction_.size(); i++)
@@ -131,27 +70,6 @@ namespace Orthanc
   }
 
 
-
-  bool LookupIdentifierQuery::IsIdentifier(const DicomTag& tag,
-                                           ResourceType level)
-  {
-    const DicomTag* tags;
-    size_t size;
-
-    LoadIdentifiers(tags, size, level);
-
-    for (size_t i = 0; i < size; i++)
-    {
-      if (tag == tags[i])
-      {
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-
   void LookupIdentifierQuery::AddConstraint(DicomTag tag,
                                             IdentifierConstraintType type,
                                             const std::string& value)
@@ -169,56 +87,6 @@ namespace Orthanc
   }
 
 
-  std::string LookupIdentifierQuery::NormalizeIdentifier(const std::string& value)
-  {
-    std::string t;
-    t.reserve(value.size());
-
-    for (size_t i = 0; i < value.size(); i++)
-    {
-      if (value[i] == '%' ||
-          value[i] == '_')
-      {
-        t.push_back(' ');  // These characters might break wildcard queries in SQL
-      }
-      else if (isascii(value[i]) &&
-               !iscntrl(value[i]) &&
-               (!isspace(value[i]) || value[i] == ' '))
-      {
-        t.push_back(value[i]);
-      }
-    }
-
-    Toolbox::ToUpperCase(t);
-
-    return Toolbox::StripSpaces(t);
-  }
-
-
-  void LookupIdentifierQuery::StoreIdentifiers(IDatabaseWrapper& database,
-                                               int64_t resource,
-                                               ResourceType level,
-                                               const DicomMap& map)
-  {
-    const DicomTag* tags;
-    size_t size;
-
-    LoadIdentifiers(tags, size, level);
-
-    for (size_t i = 0; i < size; i++)
-    {
-      const DicomValue* value = map.TestAndGetValue(tags[i]);
-      if (value != NULL &&
-          !value->IsNull() &&
-          !value->IsBinary())
-      {
-        std::string s = NormalizeIdentifier(value->GetContent());
-        database.SetIdentifierTag(resource, tags[i], s);
-      }
-    }
-  }
-
-
   void LookupIdentifierQuery::Apply(std::list<std::string>& result,
                                     IDatabaseWrapper& database)
   {
@@ -264,7 +132,7 @@ namespace Orthanc
       for (size_t j = 0; j < (*it)->GetSize(); j++)
       {
         const Constraint& c = (*it)->GetConstraint(j);
-        s << FromDcmtkBridge::GetName(c.GetTag());
+        s << FromDcmtkBridge::GetTagName(c.GetTag(), "");
 
         switch (c.GetType())
         {
diff --git a/OrthancServer/Search/LookupIdentifierQuery.h b/OrthancServer/Search/LookupIdentifierQuery.h
index fa8d9c3..0ad2708 100644
--- a/OrthancServer/Search/LookupIdentifierQuery.h
+++ b/OrthancServer/Search/LookupIdentifierQuery.h
@@ -32,7 +32,7 @@
 
 #pragma once
 
-#include "../ServerEnumerations.h"
+#include "../ServerToolbox.h"
 #include "../IDatabaseWrapper.h"
 
 #include "SetOfResources.h"
@@ -78,7 +78,7 @@ namespace Orthanc
                  const std::string& value) : 
         tag_(tag),
         type_(type),
-        value_(NormalizeIdentifier(value))
+        value_(ServerToolbox::NormalizeIdentifier(value))
       {
       }
 
@@ -138,7 +138,7 @@ namespace Orthanc
 
     bool IsIdentifier(const DicomTag& tag)
     {
-      return IsIdentifier(tag, level_);
+      return ServerToolbox::IsIdentifier(tag, level_);
     }
 
     void AddConstraint(DicomTag tag,
@@ -164,20 +164,6 @@ namespace Orthanc
     void Apply(SetOfResources& result,
                IDatabaseWrapper& database);
 
-    static void LoadIdentifiers(const DicomTag*& tags,
-                                size_t& size,
-                                ResourceType level);
-
-    static bool IsIdentifier(const DicomTag& tag,
-                             ResourceType level);
-
-    static void StoreIdentifiers(IDatabaseWrapper& database,
-                                 int64_t resource,
-                                 ResourceType level,
-                                 const DicomMap& map);
-
-    static std::string NormalizeIdentifier(const std::string& value);
-
     void Print(std::ostream& s) const;
   };
 }
diff --git a/OrthancServer/Search/LookupResource.cpp b/OrthancServer/Search/LookupResource.cpp
index 2c62a1a..b073d92 100644
--- a/OrthancServer/Search/LookupResource.cpp
+++ b/OrthancServer/Search/LookupResource.cpp
@@ -46,7 +46,7 @@ namespace Orthanc
     const DicomTag* tags = NULL;
     size_t size;
     
-    LookupIdentifierQuery::LoadIdentifiers(tags, size, level);
+    ServerToolbox::LoadIdentifiers(tags, size, level);
     
     for (size_t i = 0; i < size; i++)
     {
@@ -125,16 +125,16 @@ namespace Orthanc
         levels_[ResourceType_Patient] = new Level(ResourceType_Patient);
         break;
 
-      case ResourceType_Study:
-        levels_[ResourceType_Study] = new Level(ResourceType_Study);
+      case ResourceType_Instance:
+        levels_[ResourceType_Instance] = new Level(ResourceType_Instance);
         // Do not add "break" here
 
       case ResourceType_Series:
         levels_[ResourceType_Series] = new Level(ResourceType_Series);
         // Do not add "break" here
 
-      case ResourceType_Instance:
-        levels_[ResourceType_Instance] = new Level(ResourceType_Instance);
+      case ResourceType_Study:
+        levels_[ResourceType_Study] = new Level(ResourceType_Study);
         break;
 
       default:
diff --git a/OrthancServer/ServerContext.cpp b/OrthancServer/ServerContext.cpp
index e183296..87aedc8 100644
--- a/OrthancServer/ServerContext.cpp
+++ b/OrthancServer/ServerContext.cpp
@@ -52,6 +52,7 @@
 #include "Scheduler/StorePeerCommand.h"
 #include "OrthancRestApi/OrthancRestApi.h"
 #include "../Plugins/Engine/OrthancPlugins.h"
+#include "Search/LookupResource.h"
 
 
 #define ENABLE_DICOM_CACHE  1
@@ -85,12 +86,24 @@ namespace Orthanc
         {
           try
           {
-            it->GetListener().SignalChange(change);
+            try
+            {
+              it->GetListener().SignalChange(change);
+            }
+            catch (std::bad_alloc&)
+            {
+              LOG(ERROR) << "Not enough memory while signaling a change";
+            }
+            catch (...)
+            {
+              throw OrthancException(ErrorCode_InternalError);
+            }
           }
           catch (OrthancException& e)
           {
             LOG(ERROR) << "Error in the " << it->GetDescription() 
-                       << " callback while signaling a change: " << e.What();
+                       << " callback while signaling a change: " << e.What()
+                       << " (code " << e.GetErrorCode() << ")";
           }
         }
       }
@@ -106,16 +119,16 @@ namespace Orthanc
     storeMD5_(true),
     provider_(*this),
     dicomCache_(provider_, DICOM_CACHE_SIZE),
-    scheduler_(Configuration::GetGlobalIntegerParameter("LimitJobs", 10)),
+    scheduler_(Configuration::GetGlobalUnsignedIntegerParameter("LimitJobs", 10)),
     lua_(*this),
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
     plugins_(NULL),
 #endif
     done_(false),
-    queryRetrieveArchive_(Configuration::GetGlobalIntegerParameter("QueryRetrieveSize", 10)),
+    queryRetrieveArchive_(Configuration::GetGlobalUnsignedIntegerParameter("QueryRetrieveSize", 10)),
     defaultLocalAet_(Configuration::GetGlobalStringParameter("DicomAet", "ORTHANC"))
   {
-    uint64_t s = Configuration::GetGlobalIntegerParameter("DicomAssociationCloseDelay", 5);  // In seconds
+    uint64_t s = Configuration::GetGlobalUnsignedIntegerParameter("DicomAssociationCloseDelay", 5);  // In seconds
     scu_.SetMillisecondsBeforeClose(s * 1000);  // Milliseconds are expected here
 
     listeners_.push_back(ServerListener(lua_, "Lua"));
@@ -189,7 +202,7 @@ namespace Orthanc
       resultPublicId = hasher.HashInstance();
 
       Json::Value simplifiedTags;
-      Toolbox::SimplifyTags(simplifiedTags, dicom.GetJson(), DicomToJsonFormat_Human);
+      ServerToolbox::SimplifyTags(simplifiedTags, dicom.GetJson(), DicomToJsonFormat_Human);
 
       // Test if the instance must be filtered out
       bool accepted = true;
@@ -210,7 +223,8 @@ namespace Orthanc
           catch (OrthancException& e)
           {
             LOG(ERROR) << "Error in the " << it->GetDescription() 
-                       << " callback while receiving an instance: " << e.What();
+                       << " callback while receiving an instance: " << e.What()
+                       << " (code " << e.GetErrorCode() << ")";
             throw;
           }
         }
@@ -287,7 +301,8 @@ namespace Orthanc
           catch (OrthancException& e)
           {
             LOG(ERROR) << "Error in the " << it->GetDescription() 
-                       << " callback while receiving an instance: " << e.What();
+                       << " callback while receiving an instance: " << e.What()
+                       << " (code " << e.GetErrorCode() << ")";
           }
         }
       }
@@ -298,7 +313,7 @@ namespace Orthanc
     {
       if (e.GetErrorCode() == ErrorCode_InexistentTag)
       {
-        Toolbox::LogMissingRequiredTag(dicom.GetSummary());
+        ServerToolbox::LogMissingRequiredTag(dicom.GetSummary());
       }
 
       throw;
@@ -367,35 +382,67 @@ namespace Orthanc
   }
 
 
-  void ServerContext::ReadJson(Json::Value& result,
-                               const std::string& instancePublicId)
+  void ServerContext::ReadDicomAsJson(std::string& result,
+                                      const std::string& instancePublicId)
+  {
+    FileInfo attachment;
+    if (index_.LookupAttachment(attachment, instancePublicId, FileContentType_DicomAsJson))
+    {
+      ReadAttachment(result, attachment);
+      return;
+    }
+
+    // The "DICOM as JSON" summary is not available from the Orthanc
+    // store (most probably deleted), reconstruct it from the DICOM file
+    std::string dicom;
+    ReadDicom(dicom, instancePublicId);
+
+    LOG(INFO) << "Reconstructing the missing DICOM-as-JSON summary for instance: " << instancePublicId;
+    
+    ParsedDicomFile parsed(dicom);
+
+    Json::Value summary;
+    parsed.DatasetToJson(summary);
+
+    result = summary.toStyledString();
+
+    if (!AddAttachment(instancePublicId, FileContentType_DicomAsJson, result.c_str(), result.size()))
+    {
+      LOG(WARNING) << "Cannot associate the DICOM-as-JSON summary to instance: " << instancePublicId;
+      throw OrthancException(ErrorCode_InternalError);
+    }
+  }
+
+
+  void ServerContext::ReadDicomAsJson(Json::Value& result,
+                                      const std::string& instancePublicId)
   {
-    std::string s;
-    ReadFile(s, instancePublicId, FileContentType_DicomAsJson);
+    std::string tmp;
+    ReadDicomAsJson(tmp, instancePublicId);
 
     Json::Reader reader;
-    if (!reader.parse(s, result))
+    if (!reader.parse(tmp, result))
     {
       throw OrthancException(ErrorCode_CorruptedFile);
     }
   }
 
 
-  void ServerContext::ReadFile(std::string& result,
-                               const std::string& instancePublicId,
-                               FileContentType content,
-                               bool uncompressIfNeeded)
+  void ServerContext::ReadAttachment(std::string& result,
+                                     const std::string& instancePublicId,
+                                     FileContentType content,
+                                     bool uncompressIfNeeded)
   {
     FileInfo attachment;
     if (!index_.LookupAttachment(attachment, instancePublicId, content))
     {
+      LOG(WARNING) << "Unable to read attachment " << EnumerationToString(content) << " of instance " << instancePublicId;
       throw OrthancException(ErrorCode_InternalError);
     }
 
     if (uncompressIfNeeded)
     {
-      StorageAccessor accessor(area_);
-      accessor.Read(result, attachment);
+      ReadAttachment(result, attachment);
     }
     else
     {
@@ -406,18 +453,19 @@ namespace Orthanc
   }
 
 
-  void ServerContext::ReadFile(std::string& result,
-                               const FileInfo& file)
+  void ServerContext::ReadAttachment(std::string& result,
+                                     const FileInfo& attachment)
   {
+    // This will decompress the attachment
     StorageAccessor accessor(area_);
-    accessor.Read(result, file);
+    accessor.Read(result, attachment);
   }
 
 
   IDynamicObject* ServerContext::DicomCacheProvider::Provide(const std::string& instancePublicId)
   {
     std::string content;
-    context_.ReadFile(content, instancePublicId, FileContentType_Dicom);
+    context_.ReadDicom(content, instancePublicId);
     return new ParsedDicomFile(content);
   }
 
@@ -489,7 +537,7 @@ namespace Orthanc
   }
 
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
   void ServerContext::SetPlugins(OrthancPlugins& plugins)
   {
     boost::recursive_mutex::scoped_lock lock(listenersMutex_);
@@ -544,7 +592,7 @@ namespace Orthanc
 
   bool ServerContext::HasPlugins() const
   {
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
     return (plugins_ != NULL);
 #else
     return false;
@@ -566,7 +614,7 @@ namespace Orthanc
     for (size_t i = 0; i < instances.size(); i++)
     {
       Json::Value dicom;
-      ReadJson(dicom, instances[i]);
+      ReadDicomAsJson(dicom, instances[i]);
       
       if (lookup.IsMatch(dicom))
       {
diff --git a/OrthancServer/ServerContext.h b/OrthancServer/ServerContext.h
index 95d320b..2d97d65 100644
--- a/OrthancServer/ServerContext.h
+++ b/OrthancServer/ServerContext.h
@@ -47,7 +47,6 @@
 #include "Scheduler/ServerScheduler.h"
 #include "ServerIndex.h"
 #include "OrthancHttpHandler.h"
-#include "Search/LookupResource.h"
 
 #include <boost/filesystem.hpp>
 #include <boost/thread.hpp>
@@ -121,7 +120,7 @@ namespace Orthanc
 
     LuaScripting lua_;
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
     OrthancPlugins* plugins_;
 #endif
 
@@ -192,17 +191,26 @@ namespace Orthanc
                                      FileContentType attachmentType,
                                      CompressionType compression);
 
-    void ReadJson(Json::Value& result,
-                  const std::string& instancePublicId);
+    void ReadDicomAsJson(std::string& result,
+                         const std::string& instancePublicId);
 
-    // TODO CACHING MECHANISM AT THIS POINT
-    void ReadFile(std::string& result,
-                  const std::string& instancePublicId,
-                  FileContentType content,
-                  bool uncompressIfNeeded = true);
+    void ReadDicomAsJson(Json::Value& result,
+                         const std::string& instancePublicId);
 
-    void ReadFile(std::string& result,
-                  const FileInfo& file);
+    void ReadDicom(std::string& dicom,
+                   const std::string& instancePublicId)
+    {
+      ReadAttachment(dicom, instancePublicId, FileContentType_Dicom, true);
+    }
+    
+    // TODO CACHING MECHANISM AT THIS POINT
+    void ReadAttachment(std::string& result,
+                        const std::string& instancePublicId,
+                        FileContentType content,
+                        bool uncompressIfNeeded);
+    
+    void ReadAttachment(std::string& result,
+                        const FileInfo& attachment);
 
     void SetStoreMD5ForAttachments(bool storeMD5);
 
@@ -258,7 +266,7 @@ namespace Orthanc
      * Management of the plugins
      **/
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
     void SetPlugins(OrthancPlugins& plugins);
 
     void ResetPlugins();
diff --git a/OrthancServer/ServerEnumerations.cpp b/OrthancServer/ServerEnumerations.cpp
index 8e3fdf3..a69ef0c 100644
--- a/OrthancServer/ServerEnumerations.cpp
+++ b/OrthancServer/ServerEnumerations.cpp
@@ -64,6 +64,8 @@ namespace Orthanc
     dictMetadataType_.Add(MetadataType_AnonymizedFrom, "AnonymizedFrom");
     dictMetadataType_.Add(MetadataType_LastUpdate, "LastUpdate");
     dictMetadataType_.Add(MetadataType_Instance_Origin, "Origin");
+    dictMetadataType_.Add(MetadataType_Instance_TransferSyntax, "TransferSyntax");
+    dictMetadataType_.Add(MetadataType_Instance_SopClassUid, "SopClassUid");
 
     dictContentType_.Add(FileContentType_Dicom, "dicom");
     dictContentType_.Add(FileContentType_DicomAsJson, "dicom-as-json");
diff --git a/OrthancServer/ServerEnumerations.h b/OrthancServer/ServerEnumerations.h
index 8765680..be3f69a 100644
--- a/OrthancServer/ServerEnumerations.h
+++ b/OrthancServer/ServerEnumerations.h
@@ -157,7 +157,9 @@ namespace Orthanc
     MetadataType_ModifiedFrom = 5,
     MetadataType_AnonymizedFrom = 6,
     MetadataType_LastUpdate = 7,
-    MetadataType_Instance_Origin = 8,   // New in Orthanc 0.9.5
+    MetadataType_Instance_Origin = 8,          // New in Orthanc 0.9.5
+    MetadataType_Instance_TransferSyntax = 9,  // New in Orthanc 1.2.0
+    MetadataType_Instance_SopClassUid = 10,    // New in Orthanc 1.2.0
 
     // Make sure that the value "65535" can be stored into this enumeration
     MetadataType_StartUser = 1024,
diff --git a/OrthancServer/ServerIndex.cpp b/OrthancServer/ServerIndex.cpp
index 5cf4702..29dcfe5 100644
--- a/OrthancServer/ServerIndex.cpp
+++ b/OrthancServer/ServerIndex.cpp
@@ -40,17 +40,16 @@
 #include "ServerIndexChange.h"
 #include "EmbeddedResources.h"
 #include "OrthancInitialization.h"
+#include "ParsedDicomFile.h"
 #include "ServerToolbox.h"
 #include "../Core/Toolbox.h"
 #include "../Core/Logging.h"
-#include "../Core/Uuid.h"
 #include "../Core/DicomFormat/DicomArray.h"
-#include "Search/LookupIdentifierQuery.h"
-#include "Search/LookupResource.h"
 
 #include "FromDcmtkBridge.h"
 #include "ServerContext.h"
 #include "DicomInstanceToStore.h"
+#include "Search/LookupResource.h"
 
 #include <boost/lexical_cast.hpp>
 #include <stdio.h>
@@ -375,6 +374,8 @@ namespace Orthanc
         continue;
       }
 
+      Logging::Flush();
+
       boost::mutex::scoped_lock lock(that->mutex_);
       that->db_.FlushToDisk();
       count = 0;
@@ -593,6 +594,17 @@ namespace Orthanc
 
 
 
+  void ServerIndex::SetInstanceMetadata(std::map<MetadataType, std::string>& instanceMetadata,
+                                        int64_t instance,
+                                        MetadataType metadata,
+                                        const std::string& value)
+  {
+    db_.SetMetadata(instance, metadata, value);
+    instanceMetadata[metadata] = value;
+  }
+
+
+
   StoreStatus ServerIndex::Store(std::map<MetadataType, std::string>& instanceMetadata,
                                  DicomInstanceToStore& instanceToStore,
                                  const Attachments& attachments)
@@ -634,7 +646,7 @@ namespace Orthanc
 
       // Create the instance
       int64_t instance = CreateResource(hasher.HashInstance(), ResourceType_Instance);
-      Toolbox::SetMainDicomTags(db_, instance, ResourceType_Instance, dicomSummary);
+      ServerToolbox::StoreMainDicomTags(db_, instance, ResourceType_Instance, dicomSummary);
 
       // Detect up to which level the patient/study/series/instance
       // hierarchy must be created
@@ -686,21 +698,21 @@ namespace Orthanc
       if (isNewSeries)
       {
         series = CreateResource(hasher.HashSeries(), ResourceType_Series);
-        Toolbox::SetMainDicomTags(db_, series, ResourceType_Series, dicomSummary);
+        ServerToolbox::StoreMainDicomTags(db_, series, ResourceType_Series, dicomSummary);
       }
 
       // Create the study if needed
       if (isNewStudy)
       {
         study = CreateResource(hasher.HashStudy(), ResourceType_Study);
-        Toolbox::SetMainDicomTags(db_, study, ResourceType_Study, dicomSummary);
+        ServerToolbox::StoreMainDicomTags(db_, study, ResourceType_Study, dicomSummary);
       }
 
       // Create the patient if needed
       if (isNewPatient)
       {
         patient = CreateResource(hasher.HashPatient(), ResourceType_Patient);
-        Toolbox::SetMainDicomTags(db_, patient, ResourceType_Patient, dicomSummary);
+        ServerToolbox::StoreMainDicomTags(db_, patient, ResourceType_Patient, dicomSummary);
       }
 
       // Create the parent-to-child links
@@ -748,8 +760,7 @@ namespace Orthanc
             break;
 
           case ResourceType_Instance:
-            db_.SetMetadata(instance, it->first.second, it->second);
-            instanceMetadata[it->first.second] = it->second;
+            SetInstanceMetadata(instanceMetadata, instance, it->first.second, it->second);
             break;
 
           default:
@@ -758,34 +769,41 @@ namespace Orthanc
       }
 
       // Attach the auto-computed metadata for the patient/study/series levels
-      std::string now = Toolbox::GetNowIsoString();
+      std::string now = SystemToolbox::GetNowIsoString();
       db_.SetMetadata(series, MetadataType_LastUpdate, now);
       db_.SetMetadata(study, MetadataType_LastUpdate, now);
       db_.SetMetadata(patient, MetadataType_LastUpdate, now);
 
       // Attach the auto-computed metadata for the instance level,
       // reflecting these additions into the input metadata map
-      db_.SetMetadata(instance, MetadataType_Instance_ReceptionDate, now);
-      instanceMetadata[MetadataType_Instance_ReceptionDate] = now;
-
-      db_.SetMetadata(instance, MetadataType_Instance_RemoteAet, instanceToStore.GetRemoteAet());
-      instanceMetadata[MetadataType_Instance_RemoteAet] = instanceToStore.GetRemoteAet();
-
+      SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_ReceptionDate, now);
+      SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_RemoteAet, instanceToStore.GetRemoteAet());
+      SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_Origin, 
+                          EnumerationToString(instanceToStore.GetRequestOrigin()));
+        
       {
-        std::string s = EnumerationToString(instanceToStore.GetRequestOrigin());
-        db_.SetMetadata(instance, MetadataType_Instance_Origin, s);
-        instanceMetadata[MetadataType_Instance_Origin] = s;
+        std::string s;
+        if (instanceToStore.LookupTransferSyntax(s))
+        {
+          SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_TransferSyntax, s);
+        }
       }
 
       const DicomValue* value;
+      if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL &&
+          !value->IsNull() &&
+          !value->IsBinary())
+      {
+        SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_SopClassUid, value->GetContent());
+      }
+
       if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL ||
           (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL)
       {
         if (!value->IsNull() && 
             !value->IsBinary())
         {
-          db_.SetMetadata(instance, MetadataType_Instance_IndexInSeries, value->GetContent());
-          instanceMetadata[MetadataType_Instance_IndexInSeries] = value->GetContent();
+          SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_IndexInSeries, value->GetContent());
         }
       }
 
@@ -1214,22 +1232,34 @@ namespace Orthanc
       switch (currentType)
       {
         case ResourceType_Patient:
-          patientId = map.GetValue(DICOM_TAG_PATIENT_ID).GetContent();
+          if (map.HasTag(DICOM_TAG_PATIENT_ID))
+          {
+            patientId = map.GetValue(DICOM_TAG_PATIENT_ID).GetContent();
+          }
           done = true;
           break;
 
         case ResourceType_Study:
-          studyInstanceUid = map.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent();
+          if (map.HasTag(DICOM_TAG_STUDY_INSTANCE_UID))
+          {
+            studyInstanceUid = map.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent();
+          }
           currentType = ResourceType_Patient;
           break;
 
         case ResourceType_Series:
-          seriesInstanceUid = map.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent();
+          if (map.HasTag(DICOM_TAG_SERIES_INSTANCE_UID))
+          {
+            seriesInstanceUid = map.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent();
+          }
           currentType = ResourceType_Study;
           break;
 
         case ResourceType_Instance:
-          sopInstanceUid = map.GetValue(DICOM_TAG_SOP_INSTANCE_UID).GetContent();
+          if (map.HasTag(DICOM_TAG_SOP_INSTANCE_UID))
+          {
+            sopInstanceUid = map.GetValue(DICOM_TAG_SOP_INSTANCE_UID).GetContent();
+          }
           currentType = ResourceType_Series;
           break;
 
@@ -1250,7 +1280,7 @@ namespace Orthanc
                               type,
                               publicId,
                               remoteModality,
-                              Toolbox::GetNowIsoString(),
+                              SystemToolbox::GetNowIsoString(),
                               patientId,
                               studyInstanceUid,
                               seriesInstanceUid,
@@ -1848,7 +1878,7 @@ namespace Orthanc
 
   void ServerIndex::UnstableResourcesMonitorThread(ServerIndex* that)
   {
-    int stableAge = Configuration::GetGlobalIntegerParameter("StableAge", 60);
+    int stableAge = Configuration::GetGlobalUnsignedIntegerParameter("StableAge", 60);
     if (stableAge <= 0)
     {
       stableAge = 60;
@@ -2168,7 +2198,7 @@ namespace Orthanc
       assert(db_.GetResourceType(*it) == lookup.GetLevel());
       
       int64_t instance;
-      if (!Toolbox::FindOneChildInstance(instance, db_, *it, lookup.GetLevel()))
+      if (!ServerToolbox::FindOneChildInstance(instance, db_, *it, lookup.GetLevel()))
       {
         throw OrthancException(ErrorCode_InternalError);
       }
@@ -2209,4 +2239,67 @@ namespace Orthanc
     target = db_.GetPublicId(id);
     return true;
   }
+
+
+  void ServerIndex::ReconstructInstance(ParsedDicomFile& dicom)
+  {
+    DicomMap summary;
+    dicom.ExtractDicomSummary(summary);
+
+    DicomInstanceHasher hasher(summary);
+
+    boost::mutex::scoped_lock lock(mutex_);
+
+    try
+    {
+      Transaction t(*this);
+
+      int64_t patient = -1, study = -1, series = -1, instance = -1;
+
+      ResourceType dummy;      
+      if (!db_.LookupResource(patient, dummy, hasher.HashPatient()) ||
+          !db_.LookupResource(study, dummy, hasher.HashStudy()) ||
+          !db_.LookupResource(series, dummy, hasher.HashSeries()) ||
+          !db_.LookupResource(instance, dummy, hasher.HashInstance()) ||
+          patient == -1 ||
+          study == -1 ||
+          series == -1 ||
+          instance == -1)
+      {
+        throw OrthancException(ErrorCode_InternalError);
+      }
+
+      db_.ClearMainDicomTags(patient);
+      db_.ClearMainDicomTags(study);
+      db_.ClearMainDicomTags(series);
+      db_.ClearMainDicomTags(instance);
+
+      ServerToolbox::StoreMainDicomTags(db_, patient, ResourceType_Patient, summary);
+      ServerToolbox::StoreMainDicomTags(db_, study, ResourceType_Study, summary);
+      ServerToolbox::StoreMainDicomTags(db_, series, ResourceType_Series, summary);
+      ServerToolbox::StoreMainDicomTags(db_, instance, ResourceType_Instance, summary);
+
+      {
+        std::string s;
+        if (dicom.LookupTransferSyntax(s))
+        {
+          db_.SetMetadata(instance, MetadataType_Instance_TransferSyntax, s);
+        }
+      }
+
+      const DicomValue* value;
+      if ((value = summary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL &&
+          !value->IsNull() &&
+          !value->IsBinary())
+      {
+        db_.SetMetadata(instance, MetadataType_Instance_SopClassUid, value->GetContent());
+      }
+
+      t.Commit(0);  // No change in the DB size
+    }
+    catch (OrthancException& e)
+    {
+      LOG(ERROR) << "EXCEPTION [" << e.What() << "]";
+    }
+  }
 }
diff --git a/OrthancServer/ServerIndex.h b/OrthancServer/ServerIndex.h
index dece92d..dc2e84b 100644
--- a/OrthancServer/ServerIndex.h
+++ b/OrthancServer/ServerIndex.h
@@ -47,6 +47,7 @@ namespace Orthanc
   class LookupResource;
   class ServerContext;
   class DicomInstanceToStore;
+  class ParsedDicomFile;
 
   class ServerIndex : public boost::noncopyable
   {
@@ -115,6 +116,11 @@ namespace Orthanc
     int64_t CreateResource(const std::string& publicId,
                            ResourceType type);
 
+    void SetInstanceMetadata(std::map<MetadataType, std::string>& instanceMetadata,
+                             int64_t instance,
+                             MetadataType metadata,
+                             const std::string& value);
+
   public:
     ServerIndex(ServerContext& context,
                 IDatabaseWrapper& database);
@@ -268,5 +274,7 @@ namespace Orthanc
     bool LookupParent(std::string& target,
                       const std::string& publicId,
                       ResourceType parentType);
+
+    void ReconstructInstance(ParsedDicomFile& dicom);
   };
 }
diff --git a/OrthancServer/ServerIndexChange.h b/OrthancServer/ServerIndexChange.h
index d779840..836c5b3 100644
--- a/OrthancServer/ServerIndexChange.h
+++ b/OrthancServer/ServerIndexChange.h
@@ -34,7 +34,7 @@
 
 #include "ServerEnumerations.h"
 #include "../Core/IDynamicObject.h"
-#include "../Core/Toolbox.h"
+#include "../Core/SystemToolbox.h"
 
 #include <string>
 #include <json/value.h>
@@ -58,7 +58,7 @@ namespace Orthanc
       changeType_(changeType),
       resourceType_(resourceType),
       publicId_(publicId),
-      date_(Toolbox::GetNowIsoString())
+      date_(SystemToolbox::GetNowIsoString())
     {
     }
 
diff --git a/OrthancServer/ServerToolbox.cpp b/OrthancServer/ServerToolbox.cpp
index 0d7a877..e8589d8 100644
--- a/OrthancServer/ServerToolbox.cpp
+++ b/OrthancServer/ServerToolbox.cpp
@@ -37,15 +37,42 @@
 #include "../Core/FileStorage/StorageAccessor.h"
 #include "../Core/Logging.h"
 #include "../Core/OrthancException.h"
-#include "ParsedDicomFile.h"
-#include "Search/LookupIdentifierQuery.h"
 
 #include <cassert>
 
 namespace Orthanc
 {
-  namespace Toolbox
+  namespace ServerToolbox
   {
+    static const DicomTag patientIdentifiers[] = 
+    {
+      DICOM_TAG_PATIENT_ID,
+      DICOM_TAG_PATIENT_NAME,
+      DICOM_TAG_PATIENT_BIRTH_DATE
+    };
+
+    static const DicomTag studyIdentifiers[] = 
+    {
+      DICOM_TAG_PATIENT_ID,
+      DICOM_TAG_PATIENT_NAME,
+      DICOM_TAG_PATIENT_BIRTH_DATE,
+      DICOM_TAG_STUDY_INSTANCE_UID,
+      DICOM_TAG_ACCESSION_NUMBER,
+      DICOM_TAG_STUDY_DESCRIPTION,
+      DICOM_TAG_STUDY_DATE
+    };
+
+    static const DicomTag seriesIdentifiers[] = 
+    {
+      DICOM_TAG_SERIES_INSTANCE_UID
+    };
+
+    static const DicomTag instanceIdentifiers[] = 
+    {
+      DICOM_TAG_SOP_INSTANCE_UID
+    };
+
+
     void SimplifyTags(Json::Value& target,
                       const Json::Value& source,
                       DicomToJsonFormat format)
@@ -189,9 +216,9 @@ namespace Orthanc
     }
 
 
-    static void SetMainDicomTagsInternal(IDatabaseWrapper& database,
-                                         int64_t resource,
-                                         const DicomMap& tags)
+    static void StoreMainDicomTagsInternal(IDatabaseWrapper& database,
+                                           int64_t resource,
+                                           const DicomMap& tags)
     {
       DicomArray flattened(tags);
 
@@ -209,14 +236,38 @@ namespace Orthanc
     }
 
 
-    void SetMainDicomTags(IDatabaseWrapper& database,
-                          int64_t resource,
-                          ResourceType level,
-                          const DicomMap& dicomSummary)
+    static void StoreIdentifiers(IDatabaseWrapper& database,
+                                 int64_t resource,
+                                 ResourceType level,
+                                 const DicomMap& map)
+    {
+      const DicomTag* tags;
+      size_t size;
+
+      LoadIdentifiers(tags, size, level);
+
+      for (size_t i = 0; i < size; i++)
+      {
+        const DicomValue* value = map.TestAndGetValue(tags[i]);
+        if (value != NULL &&
+            !value->IsNull() &&
+            !value->IsBinary())
+        {
+          std::string s = NormalizeIdentifier(value->GetContent());
+          database.SetIdentifierTag(resource, tags[i], s);
+        }
+      }
+    }
+
+
+    void StoreMainDicomTags(IDatabaseWrapper& database,
+                            int64_t resource,
+                            ResourceType level,
+                            const DicomMap& dicomSummary)
     {
       // WARNING: The database should be locked with a transaction!
 
-      LookupIdentifierQuery::StoreIdentifiers(database, resource, level, dicomSummary);
+      StoreIdentifiers(database, resource, level, dicomSummary);
 
       DicomMap tags;
 
@@ -229,7 +280,7 @@ namespace Orthanc
         case ResourceType_Study:
           // Duplicate the patient tags at the study level (new in Orthanc 0.9.5 - db v6)
           dicomSummary.ExtractPatientInformation(tags);
-          SetMainDicomTagsInternal(database, resource, tags);
+          StoreMainDicomTagsInternal(database, resource, tags);
 
           dicomSummary.ExtractStudyInformation(tags);
           break;
@@ -246,7 +297,7 @@ namespace Orthanc
           throw OrthancException(ErrorCode_InternalError);
       }
 
-      SetMainDicomTagsInternal(database, resource, tags);
+      StoreMainDicomTagsInternal(database, resource, tags);
     }
 
 
@@ -282,6 +333,13 @@ namespace Orthanc
     {
       // WARNING: The database should be locked with a transaction!
 
+      // TODO: This function might consume much memory if level ==
+      // ResourceType_Instance. To improve this, first download the
+      // list of studies, then remove the instances for each single
+      // study (check out OrthancRestApi::InvalidateTags for an
+      // example). Take this improvement into consideration for the
+      // next upgrade of the database schema.
+
       const char* plural = NULL;
 
       switch (level)
@@ -347,10 +405,10 @@ namespace Orthanc
 
           // Update the tags of this resource
           DicomMap dicomSummary;
-          dicom.Convert(dicomSummary);
+          dicom.ExtractDicomSummary(dicomSummary);
 
           database.ClearMainDicomTags(resource);
-          Toolbox::SetMainDicomTags(database, resource, level, dicomSummary);
+          StoreMainDicomTags(database, resource, level, dicomSummary);
         }
         catch (OrthancException&)
         {
@@ -360,5 +418,107 @@ namespace Orthanc
         }
       }
     }
+
+
+    void LoadIdentifiers(const DicomTag*& tags,
+                         size_t& size,
+                         ResourceType level)
+    {
+      switch (level)
+      {
+        case ResourceType_Patient:
+          tags = patientIdentifiers;
+          size = sizeof(patientIdentifiers) / sizeof(DicomTag);
+          break;
+
+        case ResourceType_Study:
+          tags = studyIdentifiers;
+          size = sizeof(studyIdentifiers) / sizeof(DicomTag);
+          break;
+
+        case ResourceType_Series:
+          tags = seriesIdentifiers;
+          size = sizeof(seriesIdentifiers) / sizeof(DicomTag);
+          break;
+
+        case ResourceType_Instance:
+          tags = instanceIdentifiers;
+          size = sizeof(instanceIdentifiers) / sizeof(DicomTag);
+          break;
+
+        default:
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+    }
+
+
+    std::string NormalizeIdentifier(const std::string& value)
+    {
+      std::string t;
+      t.reserve(value.size());
+
+      for (size_t i = 0; i < value.size(); i++)
+      {
+        if (value[i] == '%' ||
+            value[i] == '_')
+        {
+          t.push_back(' ');  // These characters might break wildcard queries in SQL
+        }
+        else if (isascii(value[i]) &&
+                 !iscntrl(value[i]) &&
+                 (!isspace(value[i]) || value[i] == ' '))
+        {
+          t.push_back(value[i]);
+        }
+      }
+
+      Toolbox::ToUpperCase(t);
+
+      return Toolbox::StripSpaces(t);
+    }
+
+
+    bool IsIdentifier(const DicomTag& tag,
+                      ResourceType level)
+    {
+      const DicomTag* tags;
+      size_t size;
+
+      LoadIdentifiers(tags, size, level);
+
+      for (size_t i = 0; i < size; i++)
+      {
+        if (tag == tags[i])
+        {
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    
+    void ReconstructResource(ServerContext& context,
+                             const std::string& resource)
+    {
+      LOG(WARNING) << "Reconstructing resource " << resource;
+      
+      std::list<std::string> instances;
+      context.GetIndex().GetChildInstances(instances, resource);
+
+      for (std::list<std::string>::const_iterator 
+             it = instances.begin(); it != instances.end(); ++it)
+      {
+        ServerContext::DicomCacheLocker locker(context, *it);
+
+        Json::Value dicomAsJson;
+        locker.GetDicom().ExtractDicomAsJson(dicomAsJson);
+
+        std::string s = dicomAsJson.toStyledString();
+        context.AddAttachment(*it, FileContentType_DicomAsJson, s.c_str(), s.size());
+
+        context.GetIndex().ReconstructInstance(locker.GetDicom());
+      }
+    }
   }
 }
diff --git a/OrthancServer/ServerToolbox.h b/OrthancServer/ServerToolbox.h
index 891f38a..61a02a5 100644
--- a/OrthancServer/ServerToolbox.h
+++ b/OrthancServer/ServerToolbox.h
@@ -32,14 +32,13 @@
 
 #pragma once
 
-#include "../Core/DicomFormat/DicomMap.h"
-#include "IDatabaseWrapper.h"
+#include "ServerContext.h"
 
 #include <json/json.h>
 
 namespace Orthanc
 {
-  namespace Toolbox
+  namespace ServerToolbox
   {
     void SimplifyTags(Json::Value& target,
                       const Json::Value& source,
@@ -47,10 +46,10 @@ namespace Orthanc
 
     void LogMissingRequiredTag(const DicomMap& summary);
 
-    void SetMainDicomTags(IDatabaseWrapper& database,
-                          int64_t resource,
-                          ResourceType level,
-                          const DicomMap& dicomSummary);
+    void StoreMainDicomTags(IDatabaseWrapper& database,
+                            int64_t resource,
+                            ResourceType level,
+                            const DicomMap& dicomSummary);
 
     bool FindOneChildInstance(int64_t& result,
                               IDatabaseWrapper& database,
@@ -60,5 +59,17 @@ namespace Orthanc
     void ReconstructMainDicomTags(IDatabaseWrapper& database,
                                   IStorageArea& storageArea,
                                   ResourceType level);
+
+    void LoadIdentifiers(const DicomTag*& tags,
+                         size_t& size,
+                         ResourceType level);
+
+    bool IsIdentifier(const DicomTag& tag,
+                      ResourceType level);
+
+    std::string NormalizeIdentifier(const std::string& value);
+
+    void ReconstructResource(ServerContext& context,
+                             const std::string& resource);
   }
 }
diff --git a/OrthancServer/ToDcmtkBridge.cpp b/OrthancServer/ToDcmtkBridge.cpp
index 708293a..0fec3f4 100644
--- a/OrthancServer/ToDcmtkBridge.cpp
+++ b/OrthancServer/ToDcmtkBridge.cpp
@@ -41,24 +41,6 @@
 
 namespace Orthanc
 {
-  DcmDataset* ToDcmtkBridge::Convert(const DicomMap& map)
-  {
-    std::auto_ptr<DcmDataset> result(new DcmDataset);
-
-    for (DicomMap::Map::const_iterator 
-           it = map.map_.begin(); it != map.map_.end(); ++it)
-    {
-      if (!it->second->IsNull())
-      {
-        std::string s = it->second->GetContent();
-        DU_putStringDOElement(result.get(), Convert(it->first), s.c_str());
-      }
-    }
-
-    return result.release();
-  }
-
-
   DcmEVR ToDcmtkBridge::Convert(ValueRepresentation vr)
   {
     switch (vr)
diff --git a/OrthancServer/ToDcmtkBridge.h b/OrthancServer/ToDcmtkBridge.h
index fff8bd4..9a78367 100644
--- a/OrthancServer/ToDcmtkBridge.h
+++ b/OrthancServer/ToDcmtkBridge.h
@@ -45,8 +45,6 @@ namespace Orthanc
       return DcmTagKey(tag.GetGroup(), tag.GetElement());
     }
 
-    static DcmDataset* Convert(const DicomMap& map);
-
     static DcmEVR Convert(ValueRepresentation vr);
   };
 }
diff --git a/OrthancServer/main.cpp b/OrthancServer/main.cpp
index fc27b4a..92c4cf7 100644
--- a/OrthancServer/main.cpp
+++ b/OrthancServer/main.cpp
@@ -36,7 +36,6 @@
 #include <boost/algorithm/string/predicate.hpp>
 
 #include "../Core/Logging.h"
-#include "../Core/Uuid.h"
 #include "../Core/HttpServer/EmbeddedResourceHttpHandler.h"
 #include "../Core/HttpServer/FilesystemHttpHandler.h"
 #include "../Core/Lua/LuaFunctionCall.h"
@@ -111,8 +110,8 @@ public:
   {
     std::auto_ptr<OrthancFindRequestHandler> result(new OrthancFindRequestHandler(context_));
 
-    result->SetMaxResults(Configuration::GetGlobalIntegerParameter("LimitFindResults", 0));
-    result->SetMaxInstances(Configuration::GetGlobalIntegerParameter("LimitFindInstances", 0));
+    result->SetMaxResults(Configuration::GetGlobalUnsignedIntegerParameter("LimitFindResults", 0));
+    result->SetMaxInstances(Configuration::GetGlobalUnsignedIntegerParameter("LimitFindInstances", 0));
 
     if (result->GetMaxResults() == 0)
     {
@@ -370,7 +369,7 @@ public:
     {
       bool isPlugin = false;
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
       if (plugins_ != NULL)
       {
         plugins_->GetErrorDictionary().LogError(exception.GetErrorCode(), true);
@@ -391,7 +390,7 @@ public:
     {
       bool isPlugin = false;
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
       if (plugins_ != NULL &&
           plugins_->GetErrorDictionary().Format(message, httpStatus, exception))
       {
@@ -504,7 +503,7 @@ static void PrintErrors(const char* path)
     PrintErrorCode(ErrorCode_Plugin, "Error encountered within the plugin engine");
     PrintErrorCode(ErrorCode_NotImplemented, "Not implemented yet");
     PrintErrorCode(ErrorCode_ParameterOutOfRange, "Parameter out of range");
-    PrintErrorCode(ErrorCode_NotEnoughMemory, "Not enough memory");
+    PrintErrorCode(ErrorCode_NotEnoughMemory, "The server hosting Orthanc is running out of memory");
     PrintErrorCode(ErrorCode_BadParameterType, "Bad type for a parameter");
     PrintErrorCode(ErrorCode_BadSequenceOfCalls, "Bad sequence of calls");
     PrintErrorCode(ErrorCode_InexistentItem, "Accessing an inexistent item");
@@ -535,6 +534,7 @@ static void PrintErrors(const char* path)
     PrintErrorCode(ErrorCode_StorageAreaPlugin, "Error in the plugin implementing a custom storage area");
     PrintErrorCode(ErrorCode_EmptyRequest, "The request is empty");
     PrintErrorCode(ErrorCode_NotAcceptable, "Cannot send a response which is acceptable according to the Accept HTTP header");
+    PrintErrorCode(ErrorCode_NullPointer, "Cannot handle a NULL pointer");
     PrintErrorCode(ErrorCode_SQLiteNotOpened, "SQLite: The database is not opened");
     PrintErrorCode(ErrorCode_SQLiteAlreadyOpened, "SQLite: Connection is already open");
     PrintErrorCode(ErrorCode_SQLiteCannotOpen, "SQLite: Unable to open the database");
@@ -611,7 +611,7 @@ static void LoadLuaScripts(ServerContext& context)
     std::string path = Configuration::InterpretStringParameterAsPath(*it);
     LOG(WARNING) << "Installing the Lua scripts from: " << path;
     std::string script;
-    Toolbox::ReadFile(script, path);
+    SystemToolbox::ReadFile(script, path);
 
     LuaScripting::Locker locker(context.GetLua());
     locker.GetLua().Execute(script);
@@ -620,7 +620,7 @@ static void LoadLuaScripts(ServerContext& context)
 
 
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
 static void LoadPlugins(OrthancPlugins& plugins)
 {
   std::list<std::string> path;
@@ -643,7 +643,7 @@ static bool WaitForExit(ServerContext& context,
 {
   LOG(WARNING) << "Orthanc has started";
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
   if (context.HasPlugins())
   {
     context.GetPlugins().SignalOrthancStarted();
@@ -656,7 +656,7 @@ static bool WaitForExit(ServerContext& context,
 
   for (;;)
   {
-    ServerBarrierEvent event = Toolbox::ServerBarrier(restApi.LeaveBarrierFlag());
+    ServerBarrierEvent event = SystemToolbox::ServerBarrier(restApi.LeaveBarrierFlag());
     restart = restApi.IsResetRequestReceived();
 
     if (!restart && 
@@ -686,7 +686,7 @@ static bool WaitForExit(ServerContext& context,
 
   context.GetLua().Execute("Finalize");
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
   if (context.HasPlugins())
   {
     context.GetPlugins().SignalOrthancStopped();
@@ -722,7 +722,7 @@ static bool StartHttpServer(ServerContext& context,
   // HTTP server
   MyIncomingHttpRequestFilter httpFilter(context, plugins);
   MongooseServer httpServer;
-  httpServer.SetPortNumber(Configuration::GetGlobalIntegerParameter("HttpPort", 8042));
+  httpServer.SetPortNumber(Configuration::GetGlobalUnsignedIntegerParameter("HttpPort", 8042));
   httpServer.SetRemoteAccessAllowed(Configuration::GetGlobalBoolParameter("RemoteAccessAllowed", false));
   httpServer.SetKeepAliveEnabled(Configuration::GetGlobalBoolParameter("KeepAlive", false));
   httpServer.SetHttpCompressionEnabled(Configuration::GetGlobalBoolParameter("HttpCompressionEnabled", true));
@@ -784,8 +784,10 @@ static bool StartDicomServer(ServerContext& context,
   dicomServer.SetStoreRequestHandlerFactory(serverFactory);
   dicomServer.SetMoveRequestHandlerFactory(serverFactory);
   dicomServer.SetFindRequestHandlerFactory(serverFactory);
+  dicomServer.SetAssociationTimeout(Configuration::GetGlobalUnsignedIntegerParameter("DicomScpTimeout", 30));
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+
+#if ORTHANC_ENABLE_PLUGINS == 1
   if (plugins != NULL)
   {
     if (plugins->HasWorklistHandler())
@@ -805,7 +807,7 @@ static bool StartDicomServer(ServerContext& context,
   }
 #endif
 
-  dicomServer.SetPortNumber(Configuration::GetGlobalIntegerParameter("DicomPort", 4242));
+  dicomServer.SetPortNumber(Configuration::GetGlobalUnsignedIntegerParameter("DicomPort", 4242));
   dicomServer.SetApplicationEntityTitle(Configuration::GetGlobalStringParameter("DicomAet", "ORTHANC"));
   dicomServer.SetApplicationEntityFilter(dicomFilter);
 
@@ -849,7 +851,7 @@ static bool StartDicomServer(ServerContext& context,
 static bool ConfigureHttpHandler(ServerContext& context,
                                  OrthancPlugins *plugins)
 {
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
   // By order of priority, first apply the "plugins" layer, so that
   // plugins can overwrite the built-in REST API of Orthanc
   if (plugins)
@@ -912,7 +914,7 @@ static bool UpgradeDatabase(IDatabaseWrapper& database,
   catch (OrthancException&)
   {
     LOG(ERROR) << "Unable to run the automated upgrade, please use the replication instructions: "
-               << "https://orthanc.chu.ulg.ac.be/book/users/replication.html";
+               << "http://book.orthanc-server.com//users/replication.html";
     throw;
   }
     
@@ -932,18 +934,24 @@ static bool ConfigureServerContext(IDatabaseWrapper& database,
                                    IStorageArea& storageArea,
                                    OrthancPlugins *plugins)
 {
-  ServerContext context(database, storageArea);
-
+  // These configuration options must be set before creating the
+  // ServerContext, otherwise the possible Lua scripts will not be
+  // able to properly issue HTTP/HTTPS queries
   HttpClient::ConfigureSsl(Configuration::GetGlobalBoolParameter("HttpsVerifyPeers", true),
-                           Configuration::GetGlobalStringParameter("HttpsCACertificates", ""));
-  HttpClient::SetDefaultTimeout(Configuration::GetGlobalIntegerParameter("HttpTimeout", 0));
+                           Configuration::InterpretStringParameterAsPath
+                           (Configuration::GetGlobalStringParameter("HttpsCACertificates", "")));
+  HttpClient::SetDefaultTimeout(Configuration::GetGlobalUnsignedIntegerParameter("HttpTimeout", 0));
   HttpClient::SetDefaultProxy(Configuration::GetGlobalStringParameter("HttpProxy", ""));
+
+  DicomUserConnection::SetDefaultTimeout(Configuration::GetGlobalUnsignedIntegerParameter("DicomScuTimeout", 10));
+
+  ServerContext context(database, storageArea);
   context.SetCompressionEnabled(Configuration::GetGlobalBoolParameter("StorageCompression", false));
   context.SetStoreMD5ForAttachments(Configuration::GetGlobalBoolParameter("StoreMD5ForAttachments", true));
 
   try
   {
-    context.GetIndex().SetMaximumPatientCount(Configuration::GetGlobalIntegerParameter("MaximumPatientCount", 0));
+    context.GetIndex().SetMaximumPatientCount(Configuration::GetGlobalUnsignedIntegerParameter("MaximumPatientCount", 0));
   }
   catch (...)
   {
@@ -952,7 +960,7 @@ static bool ConfigureServerContext(IDatabaseWrapper& database,
 
   try
   {
-    uint64_t size = Configuration::GetGlobalIntegerParameter("MaximumStorageSize", 0);
+    uint64_t size = Configuration::GetGlobalUnsignedIntegerParameter("MaximumStorageSize", 0);
     context.GetIndex().SetMaximumStorageSize(size * 1024 * 1024);
   }
   catch (...)
@@ -962,7 +970,7 @@ static bool ConfigureServerContext(IDatabaseWrapper& database,
 
   LoadLuaScripts(context);
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
   if (plugins)
   {
     plugins->SetServerContext(context);
@@ -984,7 +992,7 @@ static bool ConfigureServerContext(IDatabaseWrapper& database,
 
   context.Stop();
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
   if (plugins)
   {
     plugins->ResetServerContext();
@@ -1028,7 +1036,7 @@ static bool ConfigurePlugins(int argc,
   std::auto_ptr<IDatabaseWrapper>  databasePtr;
   std::auto_ptr<IStorageArea>  storage;
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
   OrthancPlugins plugins;
   plugins.SetCommandLineArguments(argc, argv);
   LoadPlugins(plugins);
@@ -1060,7 +1068,7 @@ static bool ConfigurePlugins(int argc,
 
   return ConfigureDatabase(*database, *storage, &plugins, allowDatabaseUpgrade);
 
-#elif ORTHANC_PLUGINS_ENABLED == 0
+#elif ORTHANC_ENABLE_PLUGINS == 0
   // The plugins are disabled
   databasePtr.reset(Configuration::CreateDatabaseWrapper());
   storage.reset(Configuration::CreateStorageArea());
@@ -1068,7 +1076,7 @@ static bool ConfigurePlugins(int argc,
   return ConfigureDatabase(*databasePtr, *storage, NULL, allowDatabaseUpgrade);
 
 #else
-#  error The macro ORTHANC_PLUGINS_ENABLED must be set to 0 or 1
+#  error The macro ORTHANC_ENABLE_PLUGINS must be set to 0 or 1
 #endif
 }
 
@@ -1081,6 +1089,14 @@ static bool StartOrthanc(int argc,
 }
 
 
+static bool DisplayPerformanceWarning()
+{
+  (void) DisplayPerformanceWarning;   // Disable warning about unused function
+  LOG(WARNING) << "Performance warning: Non-release build, runtime debug assertions are turned on";
+  return true;
+}
+
+
 int main(int argc, char* argv[]) 
 {
   Logging::Initialize();
@@ -1188,7 +1204,7 @@ int main(int argc, char* argv[])
 #endif
 
       std::string target = argument.substr(9);
-      Toolbox::WriteFile(configurationSample, target);
+      SystemToolbox::WriteFile(configurationSample, target);
       return 0;
     }
     else
@@ -1209,7 +1225,7 @@ int main(int argc, char* argv[])
     {
       try
       {
-        boost::filesystem::path exe(Toolbox::GetPathToExecutable());
+        boost::filesystem::path exe(SystemToolbox::GetPathToExecutable());
         std::time_t creation = boost::filesystem::last_write_time(exe);
         boost::posix_time::ptime converted(boost::posix_time::from_time_t(creation));
         version += " (" + boost::posix_time::to_iso_string(converted) + ")";
@@ -1220,6 +1236,7 @@ int main(int argc, char* argv[])
     }
 
     LOG(WARNING) << "Orthanc version: " << version;
+    assert(DisplayPerformanceWarning());
   }
 
   int status = 0;
diff --git a/Plugins/Engine/IPluginServiceProvider.h b/Plugins/Engine/IPluginServiceProvider.h
index e6fde58..3656f22 100644
--- a/Plugins/Engine/IPluginServiceProvider.h
+++ b/Plugins/Engine/IPluginServiceProvider.h
@@ -32,7 +32,7 @@
 
 #pragma once
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
 
 #include "../Include/orthanc/OrthancCPlugin.h"
 
diff --git a/Plugins/Engine/OrthancPluginDatabase.cpp b/Plugins/Engine/OrthancPluginDatabase.cpp
index f10ab99..03b3280 100644
--- a/Plugins/Engine/OrthancPluginDatabase.cpp
+++ b/Plugins/Engine/OrthancPluginDatabase.cpp
@@ -33,7 +33,7 @@
 #include "../../OrthancServer/PrecompiledHeadersServer.h"
 #include "OrthancPluginDatabase.h"
 
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
 #error The plugin support is disabled
 #endif
 
diff --git a/Plugins/Engine/OrthancPluginDatabase.h b/Plugins/Engine/OrthancPluginDatabase.h
index 3d77948..5788eeb 100644
--- a/Plugins/Engine/OrthancPluginDatabase.h
+++ b/Plugins/Engine/OrthancPluginDatabase.h
@@ -32,7 +32,7 @@
 
 #pragma once
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
 
 #include "../../OrthancServer/IDatabaseWrapper.h"
 #include "../Include/orthanc/OrthancCDatabasePlugin.h"
diff --git a/Plugins/Engine/OrthancPlugins.cpp b/Plugins/Engine/OrthancPlugins.cpp
index a492bbf..53a5780 100644
--- a/Plugins/Engine/OrthancPlugins.cpp
+++ b/Plugins/Engine/OrthancPlugins.cpp
@@ -33,7 +33,7 @@
 #include "../../OrthancServer/PrecompiledHeadersServer.h"
 #include "OrthancPlugins.h"
 
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
 #error The plugin support is disabled
 #endif
 
@@ -563,8 +563,8 @@ namespace Orthanc
 
         case _OrthancPluginService_GetFindQueryTagName:
         {
-          const DicomTag& tag = currentQuery_->GetElement(operation.index).GetTag();
-          *operation.resultString = CopyString(FromDcmtkBridge::GetName(tag));
+          const DicomElement& element = currentQuery_->GetElement(operation.index);
+          *operation.resultString = CopyString(FromDcmtkBridge::GetTagName(element));
           break;
         }
 
@@ -687,10 +687,10 @@ namespace Orthanc
 
     virtual IMoveRequestIterator* Handle(const std::string& targetAet,
                                          const DicomMap& input,
-                                         const std::string& remoteIp,
-                                         const std::string& remoteAet,
+                                         const std::string& originatorIp,
+                                         const std::string& originatorAet,
                                          const std::string& calledAet,
-                                         uint16_t messageId)
+                                         uint16_t originatorId)
     {
       std::string levelString = ReadTag(input, DICOM_TAG_QUERY_RETRIEVE_LEVEL);
       std::string patientId = ReadTag(input, DICOM_TAG_PATIENT_ID);
@@ -712,10 +712,10 @@ namespace Orthanc
                                       studyInstanceUid.empty() ? NULL : studyInstanceUid.c_str(),
                                       seriesInstanceUid.empty() ? NULL : seriesInstanceUid.c_str(),
                                       sopInstanceUid.empty() ? NULL : sopInstanceUid.c_str(),
-                                      remoteAet.c_str(),
+                                      originatorAet.c_str(),
                                       calledAet.c_str(),
                                       targetAet.c_str(),
-                                      messageId);
+                                      originatorId);
 
       if (driver == NULL)
       {
@@ -940,7 +940,7 @@ namespace Orthanc
     }
     else
     {
-      GetErrorDictionary().LogError(error, true);
+      GetErrorDictionary().LogError(error, false);
       throw OrthancException(static_cast<ErrorCode>(error));
     }
   }
@@ -1278,7 +1278,7 @@ namespace Orthanc
 
     {
       PImpl::ServerContextLock lock(*pimpl_);
-      lock.GetContext().ReadFile(dicom, p.instanceId, FileContentType_Dicom);
+      lock.GetContext().ReadDicom(dicom, p.instanceId);
     }
 
     CopyToMemoryBuffer(*p.target, dicom);
@@ -1563,7 +1563,7 @@ namespace Orthanc
         else
         {
           Json::Value simplified;
-          Toolbox::SimplifyTags(simplified, instance.GetJson(), DicomToJsonFormat_Human);
+          ServerToolbox::SimplifyTags(simplified, instance.GetJson(), DicomToJsonFormat_Human);
           s = writer.write(simplified);
         }
 
@@ -1646,7 +1646,7 @@ namespace Orthanc
 
     if (image->IsReadOnly())
     {
-      std::auto_ptr<Image> copy(new Image(image->GetFormat(), image->GetWidth(), image->GetHeight()));
+      std::auto_ptr<Image> copy(new Image(image->GetFormat(), image->GetWidth(), image->GetHeight(), false));
       ImageProcessing::Copy(*copy, *image);
       image.reset(NULL);
       return reinterpret_cast<OrthancPluginImage*>(copy.release());
@@ -1885,7 +1885,7 @@ namespace Orthanc
     const _OrthancPluginConvertPixelFormat& p = *reinterpret_cast<const _OrthancPluginConvertPixelFormat*>(parameters);
     const ImageAccessor& source = *reinterpret_cast<const ImageAccessor*>(p.source);
 
-    std::auto_ptr<ImageAccessor> target(new Image(Plugins::Convert(p.targetFormat), source.GetWidth(), source.GetHeight()));
+    std::auto_ptr<ImageAccessor> target(new Image(Plugins::Convert(p.targetFormat), source.GetWidth(), source.GetHeight(), false));
     ImageProcessing::Convert(*target, source);
 
     *(p.target) = ReturnImage(target);
@@ -1948,15 +1948,15 @@ namespace Orthanc
 
       {
         PImpl::ServerContextLock lock(*pimpl_);
-        lock.GetContext().ReadFile(content, p.instanceId, FileContentType_Dicom);
+        lock.GetContext().ReadDicom(content, p.instanceId);
       }
 
       dicom.reset(new ParsedDicomFile(content));
     }
 
     Json::Value json;
-    dicom->ToJson(json, Plugins::Convert(p.format), 
-                  static_cast<DicomToJsonFlags>(p.flags), p.maxStringLength);
+    dicom->DatasetToJson(json, Plugins::Convert(p.format), 
+                         static_cast<DicomToJsonFlags>(p.flags), p.maxStringLength);
 
     Json::FastWriter writer;
     *p.result = CopyString(writer.write(json));
@@ -2038,7 +2038,7 @@ namespace Orthanc
     switch (service)
     {
       case _OrthancPluginService_CreateImage:
-        result.reset(new Image(Plugins::Convert(p.format), p.width, p.height));
+        result.reset(new Image(Plugins::Convert(p.format), p.width, p.height, false));
         break;
 
       case _OrthancPluginService_CreateImageAccessor:
@@ -2172,14 +2172,14 @@ namespace Orthanc
     {
       case _OrthancPluginService_GetOrthancPath:
       {
-        std::string s = Toolbox::GetPathToExecutable();
+        std::string s = SystemToolbox::GetPathToExecutable();
         *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result = CopyString(s);
         return true;
       }
 
       case _OrthancPluginService_GetOrthancDirectory:
       {
-        std::string s = Toolbox::GetDirectoryOfExecutable();
+        std::string s = SystemToolbox::GetDirectoryOfExecutable();
         *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result = CopyString(s);
         return true;
       }
@@ -2366,7 +2366,7 @@ namespace Orthanc
           *reinterpret_cast<const _OrthancPluginReadFile*>(parameters);
 
         std::string content;
-        Toolbox::ReadFile(content, p.path);
+        SystemToolbox::ReadFile(content, p.path);
         CopyToMemoryBuffer(*p.target, content.size() > 0 ? content.c_str() : NULL, content.size());
 
         return true;
@@ -2376,7 +2376,7 @@ namespace Orthanc
       {
         const _OrthancPluginWriteFile& p =
           *reinterpret_cast<const _OrthancPluginWriteFile*>(parameters);
-        Toolbox::WriteFile(p.data, p.size, p.path);
+        SystemToolbox::WriteFile(p.data, p.size, p.path);
         return true;
       }
 
@@ -2588,10 +2588,53 @@ namespace Orthanc
       case _OrthancPluginService_GenerateUuid:
       {
         *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result = 
-          CopyString(Toolbox::GenerateUuid());
+          CopyString(SystemToolbox::GenerateUuid());
+        return true;
+      }
+
+      case _OrthancPluginService_CreateFindMatcher:
+      {
+        const _OrthancPluginCreateFindMatcher& p =
+          *reinterpret_cast<const _OrthancPluginCreateFindMatcher*>(parameters);
+        ParsedDicomFile query(p.query, p.size);
+        *(p.target) = reinterpret_cast<OrthancPluginFindMatcher*>
+          (new HierarchicalMatcher(query, Configuration::GetGlobalBoolParameter("CaseSensitivePN", false)));
         return true;
       }
 
+      case _OrthancPluginService_FreeFindMatcher:
+      {
+        const _OrthancPluginFreeFindMatcher& p =
+          *reinterpret_cast<const _OrthancPluginFreeFindMatcher*>(parameters);
+
+        if (p.matcher == NULL)
+        {
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+        }
+        else
+        {
+          delete reinterpret_cast<HierarchicalMatcher*>(p.matcher);
+          return true;
+        }
+      }
+
+      case _OrthancPluginService_FindMatcherIsMatch:
+      {
+        const _OrthancPluginFindMatcherIsMatch& p =
+          *reinterpret_cast<const _OrthancPluginFindMatcherIsMatch*>(parameters);
+
+        if (p.matcher == NULL)
+        {
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+        }
+        else
+        {
+          ParsedDicomFile query(p.dicom, p.size);
+          *p.isMatch = reinterpret_cast<const HierarchicalMatcher*>(p.matcher)->Match(query) ? 1 : 0;
+          return true;
+        }
+      }
+
       default:
         return false;
     }
@@ -2758,7 +2801,17 @@ namespace Orthanc
           *reinterpret_cast<const _OrthancPluginRegisterDictionaryTag*>(parameters);
         FromDcmtkBridge::RegisterDictionaryTag(DicomTag(p.group, p.element),
                                                Plugins::Convert(p.vr), p.name,
-                                               p.minMultiplicity, p.maxMultiplicity);
+                                               p.minMultiplicity, p.maxMultiplicity, "");
+        return true;
+      }
+
+      case _OrthancPluginService_RegisterPrivateDictionaryTag:
+      {
+        const _OrthancPluginRegisterPrivateDictionaryTag& p =
+          *reinterpret_cast<const _OrthancPluginRegisterPrivateDictionaryTag*>(parameters);
+        FromDcmtkBridge::RegisterDictionaryTag(DicomTag(p.group, p.element),
+                                               Plugins::Convert(p.vr), p.name,
+                                               p.minMultiplicity, p.maxMultiplicity, p.privateCreator);
         return true;
       }
 
@@ -2774,7 +2827,7 @@ namespace Orthanc
         }
 
         IStorageArea& storage = *reinterpret_cast<IStorageArea*>(p.storageArea);
-        Toolbox::ReconstructMainDicomTags(*pimpl_->database_, storage, Plugins::Convert(p.level));
+        ServerToolbox::ReconstructMainDicomTags(*pimpl_->database_, storage, Plugins::Convert(p.level));
 
         return true;
       }
diff --git a/Plugins/Engine/OrthancPlugins.h b/Plugins/Engine/OrthancPlugins.h
index e191c04..d8cd8a5 100644
--- a/Plugins/Engine/OrthancPlugins.h
+++ b/Plugins/Engine/OrthancPlugins.h
@@ -34,7 +34,12 @@
 
 #include "PluginsErrorDictionary.h"
 
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if !defined(ORTHANC_ENABLE_PLUGINS)
+#  error The macro ORTHANC_ENABLE_PLUGINS must be defined
+#endif
+
+
+#if ORTHANC_ENABLE_PLUGINS != 1
 
 #include <boost/noncopyable.hpp>
 
diff --git a/Plugins/Engine/PluginsEnumerations.cpp b/Plugins/Engine/PluginsEnumerations.cpp
index 2d2a47c..9814b4e 100644
--- a/Plugins/Engine/PluginsEnumerations.cpp
+++ b/Plugins/Engine/PluginsEnumerations.cpp
@@ -33,7 +33,7 @@
 #include "../../OrthancServer/PrecompiledHeadersServer.h"
 #include "PluginsEnumerations.h"
 
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
 #error The plugin support is disabled
 #endif
 
diff --git a/Plugins/Engine/PluginsEnumerations.h b/Plugins/Engine/PluginsEnumerations.h
index bb42773..1540232 100644
--- a/Plugins/Engine/PluginsEnumerations.h
+++ b/Plugins/Engine/PluginsEnumerations.h
@@ -32,7 +32,7 @@
 
 #pragma once
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
 
 #include "../Include/orthanc/OrthancCPlugin.h"
 #include "../../OrthancServer/ServerEnumerations.h"
diff --git a/Plugins/Engine/PluginsErrorDictionary.cpp b/Plugins/Engine/PluginsErrorDictionary.cpp
index aba9a86..c64c5f8 100644
--- a/Plugins/Engine/PluginsErrorDictionary.cpp
+++ b/Plugins/Engine/PluginsErrorDictionary.cpp
@@ -33,7 +33,7 @@
 #include "../../OrthancServer/PrecompiledHeadersServer.h"
 #include "PluginsErrorDictionary.h"
 
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
 #error The plugin support is disabled
 #endif
 
diff --git a/Plugins/Engine/PluginsErrorDictionary.h b/Plugins/Engine/PluginsErrorDictionary.h
index 018156d..5e5214d 100644
--- a/Plugins/Engine/PluginsErrorDictionary.h
+++ b/Plugins/Engine/PluginsErrorDictionary.h
@@ -32,7 +32,7 @@
 
 #pragma once
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
 
 #include "../Include/orthanc/OrthancCPlugin.h"
 #include "../../Core/OrthancException.h"
diff --git a/Plugins/Engine/PluginsManager.cpp b/Plugins/Engine/PluginsManager.cpp
index 7a8659e..a3becba 100644
--- a/Plugins/Engine/PluginsManager.cpp
+++ b/Plugins/Engine/PluginsManager.cpp
@@ -33,7 +33,7 @@
 #include "../../OrthancServer/PrecompiledHeadersServer.h"
 #include "PluginsManager.h"
 
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
 #error The plugin support is disabled
 #endif
 
diff --git a/Plugins/Engine/PluginsManager.h b/Plugins/Engine/PluginsManager.h
index de9f45f..f04bff9 100644
--- a/Plugins/Engine/PluginsManager.h
+++ b/Plugins/Engine/PluginsManager.h
@@ -32,7 +32,7 @@
 
 #pragma once
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
 
 #include "SharedLibrary.h"
 #include "IPluginServiceProvider.h"
diff --git a/Plugins/Engine/SharedLibrary.cpp b/Plugins/Engine/SharedLibrary.cpp
index 7fefc49..1adc878 100644
--- a/Plugins/Engine/SharedLibrary.cpp
+++ b/Plugins/Engine/SharedLibrary.cpp
@@ -33,7 +33,7 @@
 #include "../../OrthancServer/PrecompiledHeadersServer.h"
 #include "SharedLibrary.h"
 
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
 #error The plugin support is disabled
 #endif
 
diff --git a/Plugins/Engine/SharedLibrary.h b/Plugins/Engine/SharedLibrary.h
index 5a7913a..330966c 100644
--- a/Plugins/Engine/SharedLibrary.h
+++ b/Plugins/Engine/SharedLibrary.h
@@ -32,7 +32,7 @@
 
 #pragma once
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
 
 #include "../../Core/OrthancException.h"
 
@@ -60,7 +60,7 @@ namespace Orthanc
     FunctionPointer GetFunctionInternal(const std::string& name);
 
   public:
-    SharedLibrary(const std::string& path);
+    explicit SharedLibrary(const std::string& path);
 
     ~SharedLibrary();
 
diff --git a/Plugins/Include/orthanc/OrthancCPlugin.h b/Plugins/Include/orthanc/OrthancCPlugin.h
index cb653d9..b9aa629 100644
--- a/Plugins/Include/orthanc/OrthancCPlugin.h
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h
@@ -116,7 +116,7 @@
 #endif
 
 #define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER     1
-#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER     1
+#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER     2
 #define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  0
 
 
@@ -191,7 +191,7 @@ extern "C"
     OrthancPluginErrorCode_Plugin = 1    /*!< Error encountered within the plugin engine */,
     OrthancPluginErrorCode_NotImplemented = 2    /*!< Not implemented yet */,
     OrthancPluginErrorCode_ParameterOutOfRange = 3    /*!< Parameter out of range */,
-    OrthancPluginErrorCode_NotEnoughMemory = 4    /*!< Not enough memory */,
+    OrthancPluginErrorCode_NotEnoughMemory = 4    /*!< The server hosting Orthanc is running out of memory */,
     OrthancPluginErrorCode_BadParameterType = 5    /*!< Bad type for a parameter */,
     OrthancPluginErrorCode_BadSequenceOfCalls = 6    /*!< Bad sequence of calls */,
     OrthancPluginErrorCode_InexistentItem = 7    /*!< Accessing an inexistent item */,
@@ -222,6 +222,7 @@ extern "C"
     OrthancPluginErrorCode_StorageAreaPlugin = 32    /*!< Error in the plugin implementing a custom storage area */,
     OrthancPluginErrorCode_EmptyRequest = 33    /*!< The request is empty */,
     OrthancPluginErrorCode_NotAcceptable = 34    /*!< Cannot send a response which is acceptable according to the Accept HTTP header */,
+    OrthancPluginErrorCode_NullPointer = 35    /*!< Cannot handle a NULL pointer */,
     OrthancPluginErrorCode_SQLiteNotOpened = 1000    /*!< SQLite: The database is not opened */,
     OrthancPluginErrorCode_SQLiteAlreadyOpened = 1001    /*!< SQLite: Connection is already open */,
     OrthancPluginErrorCode_SQLiteCannotOpen = 1002    /*!< SQLite: Unable to open the database */,
@@ -407,6 +408,7 @@ extern "C"
     _OrthancPluginService_LookupDictionary = 26,
     _OrthancPluginService_CallHttpClient2 = 27,
     _OrthancPluginService_GenerateUuid = 28,
+    _OrthancPluginService_RegisterPrivateDictionaryTag = 29,
 
     /* Registration of callbacks */
     _OrthancPluginService_RegisterRestCallback = 1000,
@@ -499,6 +501,9 @@ extern "C"
     _OrthancPluginService_GetFindQueryTag = 7007,
     _OrthancPluginService_GetFindQueryTagName = 7008,
     _OrthancPluginService_GetFindQueryValue = 7009,
+    _OrthancPluginService_CreateFindMatcher = 7010,
+    _OrthancPluginService_FreeFindMatcher = 7011,
+    _OrthancPluginService_FindMatcherIsMatch = 7012,
 
     _OrthancPluginService_INTERNAL = 0x7fffffff
   } _OrthancPluginService;
@@ -712,6 +717,7 @@ extern "C"
    **/
   typedef enum
   {
+    OrthancPluginDicomToJsonFlags_None                  = 0,
     OrthancPluginDicomToJsonFlags_IncludeBinary         = (1 << 0),  /*!< Include the binary tags */
     OrthancPluginDicomToJsonFlags_IncludePrivateTags    = (1 << 1),  /*!< Include the private tags */
     OrthancPluginDicomToJsonFlags_IncludeUnknownTags    = (1 << 2),  /*!< Include the tags unknown by the dictionary */
@@ -730,6 +736,7 @@ extern "C"
    **/
   typedef enum
   {
+    OrthancPluginCreateDicomFlags_None                  = 0,
     OrthancPluginCreateDicomFlags_DecodeDataUriScheme   = (1 << 0),  /*!< Decode fields encoded using data URI scheme */
     OrthancPluginCreateDicomFlags_GenerateIdentifiers   = (1 << 1),  /*!< Automatically generate DICOM identifiers */
 
@@ -854,6 +861,14 @@ extern "C"
 
 
   /**
+   * @brief Opaque structure to an object that can be used to check whether a DICOM instance matches a C-Find query.
+   * @ingroup Toolbox
+   **/
+  typedef struct _OrthancPluginFindAnswers_t OrthancPluginFindMatcher;
+
+
+
+  /**
    * @brief Signature of a callback function that answers to a REST request.
    * @ingroup Callbacks
    **/
@@ -1044,18 +1059,20 @@ extern "C"
    * @param resourceType The type of the resource of interest. Note
    * that this might be set to ResourceType_None if the
    * QueryRetrieveLevel (0008,0052) tag was not provided by the
-   * issuer.
+   * issuer (i.e. the originator modality).
    * @param patientId Content of the PatientID (0x0010, 0x0020) tag of the resource of interest. Might be NULL.
    * @param accessionNumber Content of the AccessionNumber (0x0008, 0x0050) tag. Might be NULL.
    * @param studyInstanceUid Content of the StudyInstanceUID (0x0020, 0x000d) tag. Might be NULL.
    * @param seriesInstanceUid Content of the SeriesInstanceUID (0x0020, 0x000e) tag. Might be NULL.
    * @param sopInstanceUid Content of the SOPInstanceUID (0x0008, 0x0018) tag. Might be NULL.
-   * @param issuerAet The Application Entity Title (AET) of the
+   * @param originatorAet The Application Entity Title (AET) of the
    * modality from which the request originates.
    * @param sourceAet The Application Entity Title (AET) of the
    * modality that should send its DICOM files to another modality.
    * @param targetAet The Application Entity Title (AET) of the
    * modality that should receive the DICOM files.
+   * @param originatorId The Message ID issued by the originator modality,
+   * as found in tag (0000,0110) of the DICOM query emitted by the issuer.
    *
    * @return The NULL value if the plugin cannot deal with this query,
    * or a pointer to the driver object that is responsible for
@@ -1071,10 +1088,10 @@ extern "C"
     const char*                studyInstanceUid,
     const char*                seriesInstanceUid,
     const char*                sopInstanceUid,
-    const char*                issuerAet,
+    const char*                originatorAet,
     const char*                sourceAet,
     const char*                targetAet,
-    uint16_t                   moveOriginatorId);
+    uint16_t                   originatorId);
     
 
   /**
@@ -4091,9 +4108,9 @@ extern "C"
   /**
    * @brief Register a new tag into the DICOM dictionary.
    *
-   * This function declares a new tag in the dictionary of DICOM tags
-   * that are known to Orthanc. This function should be used in the
-   * OrthancPluginInitialize() callback.
+   * This function declares a new public tag in the dictionary of
+   * DICOM tags that are known to Orthanc. This function should be
+   * used in the OrthancPluginInitialize() callback.
    *
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param group The group of the tag.
@@ -4104,6 +4121,7 @@ extern "C"
    * @param maxMultiplicity The maximum multiplicity of the tag. A value of 0 means
    * an arbitrary multiplicity ("<tt>n</tt>").
    * @return 0 if success, other value if error.
+   * @see OrthancPluginRegisterPrivateDictionaryTag()
    * @ingroup Toolbox
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRegisterDictionaryTag(
@@ -4128,6 +4146,60 @@ extern "C"
 
 
 
+  typedef struct
+  {
+    uint16_t                          group;
+    uint16_t                          element;
+    OrthancPluginValueRepresentation  vr;
+    const char*                       name;
+    uint32_t                          minMultiplicity;
+    uint32_t                          maxMultiplicity;
+    const char*                       privateCreator;
+  } _OrthancPluginRegisterPrivateDictionaryTag;
+  
+  /**
+   * @brief Register a new private tag into the DICOM dictionary.
+   *
+   * This function declares a new private tag in the dictionary of
+   * DICOM tags that are known to Orthanc. This function should be
+   * used in the OrthancPluginInitialize() callback.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param group The group of the tag.
+   * @param element The element of the tag.
+   * @param vr The value representation of the tag.
+   * @param name The nickname of the tag.
+   * @param minMultiplicity The minimum multiplicity of the tag (must be above 0).
+   * @param maxMultiplicity The maximum multiplicity of the tag. A value of 0 means
+   * an arbitrary multiplicity ("<tt>n</tt>").
+   * @param privateCreator The private creator of this private tag.
+   * @return 0 if success, other value if error.
+   * @see OrthancPluginRegisterDictionaryTag()
+   * @ingroup Toolbox
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode  OrthancPluginRegisterPrivateDictionaryTag(
+    OrthancPluginContext*             context,
+    uint16_t                          group,
+    uint16_t                          element,
+    OrthancPluginValueRepresentation  vr,
+    const char*                       name,
+    uint32_t                          minMultiplicity,
+    uint32_t                          maxMultiplicity,
+    const char*                       privateCreator)
+  {
+    _OrthancPluginRegisterPrivateDictionaryTag params;
+    params.group = group;
+    params.element = element;
+    params.vr = vr;
+    params.name = name;
+    params.minMultiplicity = minMultiplicity;
+    params.maxMultiplicity = maxMultiplicity;
+    params.privateCreator = privateCreator;
+
+    return context->InvokeService(context, _OrthancPluginService_RegisterPrivateDictionaryTag, &params);
+  }
+
+
 
   typedef struct
   {
@@ -5355,6 +5427,123 @@ extern "C"
 
 
 
+  typedef struct
+  {
+    OrthancPluginFindMatcher** target;
+    const void*                query;
+    uint32_t                   size;
+  } _OrthancPluginCreateFindMatcher;
+
+
+  /**
+   * @brief Create a C-Find matcher.
+   *
+   * This function creates a "matcher" object that can be used to
+   * check whether a DICOM instance matches a C-Find query. The C-Find
+   * query must be expressed as a DICOM buffer.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param query The C-Find DICOM query.
+   * @param size The size of the DICOM query.
+   * @return The newly allocated matcher. It must be freed with OrthancPluginFreeFindMatcher().
+   * @ingroup Toolbox
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginFindMatcher* OrthancPluginCreateFindMatcher(
+    OrthancPluginContext*  context,
+    const void*            query,
+    uint32_t               size)
+  {
+    OrthancPluginFindMatcher* target = NULL;
+
+    _OrthancPluginCreateFindMatcher params;
+    memset(&params, 0, sizeof(params));
+    params.target = ⌖
+    params.query = query;
+    params.size = size;
+
+    if (context->InvokeService(context, _OrthancPluginService_CreateFindMatcher, &params) != OrthancPluginErrorCode_Success)
+    {
+      return NULL;
+    }
+    else
+    {
+      return target;
+    }
+  }
+
+
+  typedef struct
+  {
+    OrthancPluginFindMatcher*   matcher;
+  } _OrthancPluginFreeFindMatcher;
+
+  /**
+   * @brief Free a C-Find matcher.
+   *
+   * This function frees a matcher that was created using OrthancPluginCreateFindMatcher().
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param matcher The matcher of interest.
+   * @ingroup Toolbox
+   **/
+  ORTHANC_PLUGIN_INLINE void  OrthancPluginFreeFindMatcher(
+    OrthancPluginContext*     context, 
+    OrthancPluginFindMatcher* matcher)
+  {
+    _OrthancPluginFreeFindMatcher params;
+    params.matcher = matcher;
+
+    context->InvokeService(context, _OrthancPluginService_FreeFindMatcher, &params);
+  }
+
+
+  typedef struct
+  {
+    const OrthancPluginFindMatcher*  matcher;
+    const void*                      dicom;
+    uint32_t                         size;
+    int32_t*                         isMatch;
+  } _OrthancPluginFindMatcherIsMatch;
+
+  /**
+   * @brief Test whether a DICOM instance matches a C-Find query.
+   *
+   * This function checks whether one DICOM instance matches C-Find
+   * matcher that was previously allocated using
+   * OrthancPluginCreateFindMatcher().
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param matcher The matcher of interest.
+   * @param dicom The DICOM instance to be matched.
+   * @param size The size of the DICOM instance.
+   * @return 1 if the DICOM instance matches the query, 0 otherwise.
+   * @ingroup Toolbox
+   **/
+  ORTHANC_PLUGIN_INLINE int32_t  OrthancPluginFindMatcherIsMatch(
+    OrthancPluginContext*            context,
+    const OrthancPluginFindMatcher*  matcher,
+    const void*                      dicom,
+    uint32_t                         size)
+  {
+    int32_t isMatch = 0;
+
+    _OrthancPluginFindMatcherIsMatch params;
+    params.matcher = matcher;
+    params.dicom = dicom;
+    params.size = size;
+    params.isMatch = &isMatch;
+
+    if (context->InvokeService(context, _OrthancPluginService_FindMatcherIsMatch, &params) == OrthancPluginErrorCode_Success)
+    {
+      return isMatch;
+    }
+    else
+    {
+      /* Error: Assume non-match */
+      return 0;
+    }
+  }
+
 
 #ifdef  __cplusplus
 }
diff --git a/Plugins/Samples/Basic/Plugin.c b/Plugins/Samples/Basic/Plugin.c
index 36b30bb..b30e4da 100644
--- a/Plugins/Samples/Basic/Plugin.c
+++ b/Plugins/Samples/Basic/Plugin.c
@@ -28,9 +28,9 @@ static OrthancPluginContext* context = NULL;
 static OrthancPluginErrorCode customError;
 
 
-ORTHANC_PLUGINS_API int32_t Callback1(OrthancPluginRestOutput* output,
-                                      const char* url,
-                                      const OrthancPluginHttpRequest* request)
+ORTHANC_PLUGINS_API OrthancPluginErrorCode Callback1(OrthancPluginRestOutput* output,
+                                                     const char* url,
+                                                     const OrthancPluginHttpRequest* request)
 {
   char buffer[1024];
   uint32_t i;
@@ -57,7 +57,7 @@ ORTHANC_PLUGINS_API int32_t Callback1(OrthancPluginRestOutput* output,
     OrthancPluginLogWarning(context, buffer);    
   }
 
-  OrthancPluginLogWarning(context, "");    
+  OrthancPluginLogWarning(context, "");
 
   for (i = 0; i < request->headersCount; i++)
   {
@@ -67,13 +67,13 @@ ORTHANC_PLUGINS_API int32_t Callback1(OrthancPluginRestOutput* output,
 
   OrthancPluginLogWarning(context, "");
 
-  return 1;
+  return OrthancPluginErrorCode_Success;
 }
 
 
-ORTHANC_PLUGINS_API int32_t Callback2(OrthancPluginRestOutput* output,
-                                      const char* url,
-                                      const OrthancPluginHttpRequest* request)
+ORTHANC_PLUGINS_API OrthancPluginErrorCode Callback2(OrthancPluginRestOutput* output,
+                                                     const char* url,
+                                                     const OrthancPluginHttpRequest* request)
 {
   /* Answer with a sample 16bpp image. */
 
@@ -99,13 +99,13 @@ ORTHANC_PLUGINS_API int32_t Callback2(OrthancPluginRestOutput* output,
                                            256, 256, sizeof(uint16_t) * 256, buffer);
   }
 
-  return 0;
+  return OrthancPluginErrorCode_Success;
 }
 
 
-ORTHANC_PLUGINS_API int32_t Callback3(OrthancPluginRestOutput* output,
-                                      const char* url,
-                                      const OrthancPluginHttpRequest* request)
+ORTHANC_PLUGINS_API OrthancPluginErrorCode Callback3(OrthancPluginRestOutput* output,
+                                                     const char* url,
+                                                     const OrthancPluginHttpRequest* request)
 {
   if (request->method != OrthancPluginHttpMethod_Get)
   {
@@ -124,13 +124,13 @@ ORTHANC_PLUGINS_API int32_t Callback3(OrthancPluginRestOutput* output,
     }
   }
 
-  return 0;
+  return OrthancPluginErrorCode_Success;
 }
 
 
-ORTHANC_PLUGINS_API int32_t Callback4(OrthancPluginRestOutput* output,
-                                      const char* url,
-                                      const OrthancPluginHttpRequest* request)
+ORTHANC_PLUGINS_API OrthancPluginErrorCode Callback4(OrthancPluginRestOutput* output,
+                                                     const char* url,
+                                                     const OrthancPluginHttpRequest* request)
 {
   /* Answer with a sample 8bpp image. */
 
@@ -156,13 +156,13 @@ ORTHANC_PLUGINS_API int32_t Callback4(OrthancPluginRestOutput* output,
                                            256, 256, 256, buffer);
   }
 
-  return 0;
+  return OrthancPluginErrorCode_Success;
 }
 
 
-ORTHANC_PLUGINS_API int32_t Callback5(OrthancPluginRestOutput* output,
-                                      const char* url,
-                                      const OrthancPluginHttpRequest* request)
+ORTHANC_PLUGINS_API OrthancPluginErrorCode Callback5(OrthancPluginRestOutput* output,
+                                                     const char* url,
+                                                     const OrthancPluginHttpRequest* request)
 {
   /**
    * Demonstration the difference between the
@@ -199,13 +199,13 @@ ORTHANC_PLUGINS_API int32_t Callback5(OrthancPluginRestOutput* output,
 
   if (error)
   {
-    return -1;
+    return OrthancPluginErrorCode_InternalError;
   }
   else
   {
     OrthancPluginAnswerBuffer(context, output, tmp.data, tmp.size, "application/octet-stream");
     OrthancPluginFreeMemoryBuffer(context, &tmp);
-    return 0;
+    return OrthancPluginErrorCode_Success;
   }
 }
 
diff --git a/Plugins/Samples/Common/DicomDatasetReader.cpp b/Plugins/Samples/Common/DicomDatasetReader.cpp
new file mode 100644
index 0000000..b354bb1
--- /dev/null
+++ b/Plugins/Samples/Common/DicomDatasetReader.cpp
@@ -0,0 +1,122 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "DicomDatasetReader.h"
+
+#include "OrthancPluginCppWrapper.h"
+
+#include <boost/lexical_cast.hpp>
+
+namespace OrthancPlugins
+{
+  // This function is copied-pasted from "../../../Core/Toolbox.cpp",
+  // in order to avoid the dependency of plugins against the Orthanc core
+  static std::string StripSpaces(const std::string& source)
+  {
+    size_t first = 0;
+
+    while (first < source.length() &&
+           isspace(source[first]))
+    {
+      first++;
+    }
+
+    if (first == source.length())
+    {
+      // String containing only spaces
+      return "";
+    }
+
+    size_t last = source.length();
+    while (last > first &&
+           isspace(source[last - 1]))
+    {
+      last--;
+    }          
+    
+    assert(first <= last);
+    return source.substr(first, last - first);
+  }
+
+
+  DicomDatasetReader::DicomDatasetReader(IDicomDataset* dataset) :  // takes ownership
+    dataset_(dataset)
+  {
+    if (dataset == NULL)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
+    }
+  }
+  
+
+  std::string DicomDatasetReader::GetMandatoryStringValue(const DicomPath& path) const
+  {
+    std::string s;
+    if (dataset_->GetStringValue(s, path))
+    {
+      return s;
+    }
+    else
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InexistentTag);
+    }
+  }
+
+
+  int DicomDatasetReader::GetIntegerValue(const DicomPath& path)
+  {
+    try
+    {
+      std::string s = StripSpaces(GetMandatoryStringValue(path));
+      return boost::lexical_cast<int>(s);
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);        
+    }
+  }
+
+
+  unsigned int DicomDatasetReader::GetUnsignedIntegerValue(const DicomPath& path)
+  {
+    int value = GetIntegerValue(path);
+
+    if (value >= 0)
+    {
+      return static_cast<unsigned int>(value);
+    }
+    else
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
+    }
+  }
+}
diff --git a/Core/DicomFormat/DicomArray.h b/Plugins/Samples/Common/DicomDatasetReader.h
similarity index 77%
copy from Core/DicomFormat/DicomArray.h
copy to Plugins/Samples/Common/DicomDatasetReader.h
index a223685..0074071 100644
--- a/Core/DicomFormat/DicomArray.h
+++ b/Plugins/Samples/Common/DicomDatasetReader.h
@@ -32,35 +32,29 @@
 
 #pragma once
 
-#include "DicomElement.h"
-#include "DicomMap.h"
+#include "IDicomDataset.h"
 
-#include <vector>
+#include <memory>
 
-namespace Orthanc
+namespace OrthancPlugins
 {
-  class DicomArray : public boost::noncopyable
+  class DicomDatasetReader : public boost::noncopyable
   {
   private:
-    typedef std::vector<DicomElement*>  Elements;
-
-    Elements  elements_;
+    std::auto_ptr<IDicomDataset>  dataset_;
 
   public:
-    DicomArray(const DicomMap& map);
-
-    ~DicomArray();
+    DicomDatasetReader(IDicomDataset* dataset);  // takes ownership
 
-    size_t GetSize() const
+    IDicomDataset& GetDataset() const
     {
-      return elements_.size();
+      return *dataset_;
     }
 
-    const DicomElement& GetElement(size_t i) const
-    {
-      return *elements_[i];
-    }
+    std::string GetMandatoryStringValue(const DicomPath& path) const;
+
+    int GetIntegerValue(const DicomPath& path);
 
-    void Print(FILE* fp) const;
+    unsigned int GetUnsignedIntegerValue(const DicomPath& path);
   };
 }
diff --git a/Core/DicomFormat/DicomValue.cpp b/Plugins/Samples/Common/DicomPath.cpp
similarity index 57%
copy from Core/DicomFormat/DicomValue.cpp
copy to Plugins/Samples/Common/DicomPath.cpp
index 32a17b5..3437e60 100644
--- a/Core/DicomFormat/DicomValue.cpp
+++ b/Plugins/Samples/Common/DicomPath.cpp
@@ -30,64 +30,57 @@
  **/
 
 
-#include "../PrecompiledHeaders.h"
-#include "DicomValue.h"
+#include "DicomPath.h"
 
-#include "../OrthancException.h"
-#include "../Toolbox.h"
+#include "OrthancPluginCppWrapper.h"
 
-namespace Orthanc
+namespace OrthancPlugins
 {
-  DicomValue::DicomValue(const DicomValue& other) : 
-    type_(other.type_),
-    content_(other.content_)
+  const DicomPath::Prefix& DicomPath::GetPrefixItem(size_t depth) const
   {
-  }
-
-
-  DicomValue::DicomValue(const std::string& content,
-                         bool isBinary) :
-    type_(isBinary ? Type_Binary : Type_String),
-    content_(content)
-  {
-  }
-  
-  
-  DicomValue::DicomValue(const char* data,
-                         size_t size,
-                         bool isBinary) :
-    type_(isBinary ? Type_Binary : Type_String)
-  {
-    content_.assign(data, size);
-  }
-    
-  
-  const std::string& DicomValue::GetContent() const
-  {
-    if (type_ == Type_Null)
+    if (depth >= prefix_.size())
     {
-      throw OrthancException(ErrorCode_BadParameterType);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
     }
     else
     {
-      return content_;
+      return prefix_[depth];
     }
   }
 
 
-  DicomValue* DicomValue::Clone() const
+  DicomPath::DicomPath(const DicomTag& sequence,
+                       size_t index,
+                       const DicomTag& tag) :
+    finalTag_(tag)
   {
-    return new DicomValue(*this);
+    AddToPrefix(sequence, index);
   }
 
-  
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
-  void DicomValue::FormatDataUriScheme(std::string& target,
-                                       const std::string& mime) const
+
+  DicomPath::DicomPath(const DicomTag& sequence1,
+                       size_t index1,
+                       const DicomTag& sequence2,
+                       size_t index2,
+                       const DicomTag& tag) :
+    finalTag_(tag)
   {
-    Toolbox::EncodeBase64(target, GetContent());
-    target.insert(0, "data:" + mime + ";base64,");
+    AddToPrefix(sequence1, index1);
+    AddToPrefix(sequence2, index2);
   }
-#endif
 
+
+  DicomPath::DicomPath(const DicomTag& sequence1,
+                       size_t index1,
+                       const DicomTag& sequence2,
+                       size_t index2,
+                       const DicomTag& sequence3,
+                       size_t index3,
+                       const DicomTag& tag) :
+    finalTag_(tag)
+  {
+    AddToPrefix(sequence1, index1);
+    AddToPrefix(sequence2, index2);
+    AddToPrefix(sequence3, index3);
+  }
 }
diff --git a/Core/Images/ImageBuffer.h b/Plugins/Samples/Common/DicomPath.h
similarity index 56%
copy from Core/Images/ImageBuffer.h
copy to Plugins/Samples/Common/DicomPath.h
index 381269e..f14f051 100644
--- a/Core/Images/ImageBuffer.h
+++ b/Plugins/Samples/Common/DicomPath.h
@@ -32,84 +32,76 @@
 
 #pragma once
 
-#include "ImageAccessor.h"
+#include "DicomTag.h"
 
 #include <vector>
-#include <stdint.h>
-#include <boost/noncopyable.hpp>
+#include <stddef.h>
 
-namespace Orthanc
+namespace OrthancPlugins
 {
-  class ImageBuffer : public boost::noncopyable
+  class DicomPath
   {
   private:
-    bool changed_;
+    typedef std::pair<DicomTag, size_t>  Prefix;
 
-    bool forceMinimalPitch_;  // Currently unused
-    PixelFormat format_;
-    unsigned int width_;
-    unsigned int height_;
-    unsigned int pitch_;
-    void *buffer_;
+    std::vector<Prefix>  prefix_;
+    DicomTag             finalTag_;
 
-    void Initialize();
-    
-    void Allocate();
-
-    void Deallocate();
+    const Prefix& GetPrefixItem(size_t depth) const;
 
   public:
-    ImageBuffer(PixelFormat format,
-                unsigned int width,
-                unsigned int height);
-
-    ImageBuffer()
+    DicomPath(const DicomTag& finalTag) :
+    finalTag_(finalTag)
     {
-      Initialize();
     }
 
-    ~ImageBuffer()
+    DicomPath(const DicomTag& sequence,
+              size_t index,
+              const DicomTag& tag);
+
+    DicomPath(const DicomTag& sequence1,
+              size_t index1,
+              const DicomTag& sequence2,
+              size_t index2,
+              const DicomTag& tag);
+
+    DicomPath(const DicomTag& sequence1,
+              size_t index1,
+              const DicomTag& sequence2,
+              size_t index2,
+              const DicomTag& sequence3,
+              size_t index3,
+              const DicomTag& tag);
+
+    void AddToPrefix(const DicomTag& tag,
+                     size_t position)
     {
-      Deallocate();
+      prefix_.push_back(std::make_pair(tag, position));
     }
 
-    PixelFormat GetFormat() const
+    size_t GetPrefixLength() const
     {
-      return format_;
+      return prefix_.size();
     }
-
-    void SetFormat(PixelFormat format);
-
-    unsigned int GetWidth() const
+    
+    DicomTag GetPrefixTag(size_t depth) const
     {
-      return width_;
+      return GetPrefixItem(depth).first;
     }
 
-    void SetWidth(unsigned int width);
-
-    unsigned int GetHeight() const
+    size_t GetPrefixIndex(size_t depth) const
     {
-      return height_;
+      return GetPrefixItem(depth).second;
     }
-
-    void SetHeight(unsigned int height);
-
-    unsigned int GetBytesPerPixel() const
+    
+    const DicomTag& GetFinalTag() const
     {
-      return ::Orthanc::GetBytesPerPixel(format_);
+      return finalTag_;
     }
 
-    ImageAccessor GetAccessor();
-
-    ImageAccessor GetConstAccessor();
-
-    bool IsMinimalPitchForced() const
+    void SetFinalTag(const DicomTag& tag)
     {
-      return forceMinimalPitch_;
+      finalTag_ = tag;
     }
-
-    void SetMinimalPitchForced(bool force);
-
-    void AcquireOwnership(ImageBuffer& other);
   };
 }
diff --git a/Core/DicomFormat/DicomImageInformation.h b/Plugins/Samples/Common/DicomTag.cpp
similarity index 51%
copy from Core/DicomFormat/DicomImageInformation.h
copy to Plugins/Samples/Common/DicomTag.cpp
index 568e6e3..040d885 100644
--- a/Core/DicomFormat/DicomImageInformation.h
+++ b/Plugins/Samples/Common/DicomTag.cpp
@@ -30,98 +30,81 @@
  **/
 
 
-#pragma once
+#include "DicomTag.h"
 
-#include "DicomMap.h"
+#include "OrthancPluginCppWrapper.h"
 
-#include <stdint.h>
-
-namespace Orthanc
+namespace OrthancPlugins
 {
-  class DicomImageInformation
+  const char* DicomTag::GetName() const
   {
-  private:
-    unsigned int width_;
-    unsigned int height_;
-    unsigned int samplesPerPixel_;
-    unsigned int numberOfFrames_;
-
-    bool isPlanar_;
-    bool isSigned_;
-    size_t bytesPerValue_;
-
-    unsigned int bitsAllocated_;
-    unsigned int bitsStored_;
-    unsigned int highBit_;
-
-    PhotometricInterpretation  photometric_;
-
-  public:
-    DicomImageInformation(const DicomMap& values);
-
-    unsigned int GetWidth() const
+    if (*this == DICOM_TAG_BITS_STORED)
     {
-      return width_;
+      return "BitsStored";
     }
-
-    unsigned int GetHeight() const
+    else if (*this == DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)
     {
-      return height_;
+      return "ColumnPositionInTotalImagePixelMatrix";
     }
-
-    unsigned int GetNumberOfFrames() const
+    else if (*this == DICOM_TAG_COLUMNS)
     {
-      return numberOfFrames_;
+      return "Columns";
     }
-
-    unsigned int GetChannelCount() const
+    else if (*this == DICOM_TAG_MODALITY)
     {
-      return samplesPerPixel_;
+      return "Modality";
     }
-
-    unsigned int GetBitsStored() const
+    else if (*this == DICOM_TAG_NUMBER_OF_FRAMES)
     {
-      return bitsStored_;
+      return "NumberOfFrames";
     }
-
-    size_t GetBytesPerValue() const
+    else if (*this == DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE)
     {
-      return bytesPerValue_;
+      return "PerFrameFunctionalGroupsSequence";
     }
-
-    bool IsSigned() const
+    else if (*this == DICOM_TAG_PHOTOMETRIC_INTERPRETATION)
     {
-      return isSigned_;
+      return "PhotometricInterpretation";
     }
-
-    unsigned int GetBitsAllocated() const
+    else if (*this == DICOM_TAG_PIXEL_REPRESENTATION)
     {
-      return bitsAllocated_;
+      return "PixelRepresentation";
     }
-
-    unsigned int GetHighBit() const
+    else if (*this == DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE)
     {
-      return highBit_;
+      return "PlanePositionSlideSequence";
     }
-
-    bool IsPlanar() const
+    else if (*this == DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)
     {
-      return isPlanar_;
+      return "RowPositionInTotalImagePixelMatrix";
     }
-
-    unsigned int GetShift() const
+    else if (*this == DICOM_TAG_ROWS)
     {
-      return highBit_ + 1 - bitsStored_;
+      return "Rows";
     }
-
-    PhotometricInterpretation GetPhotometricInterpretation() const
+    else if (*this == DICOM_TAG_SOP_CLASS_UID)
     {
-      return photometric_;
+      return "SOPClassUID";
     }
-
-    bool ExtractPixelFormat(PixelFormat& format,
-                            bool ignorePhotometricInterpretation) const;
-
-    size_t GetFrameSize() const;
-  };
+    else if (*this == DICOM_TAG_SAMPLES_PER_PIXEL)
+    {
+      return "SamplesPerPixel";
+    }
+    else if (*this == DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS)
+    {
+      return "TotalPixelMatrixColumns";
+    }
+    else if (*this == DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS)
+    {
+      return "TotalPixelMatrixRows";
+    }
+    else if (*this == DICOM_TAG_TRANSFER_SYNTAX_UID)
+    {
+      return "TransferSyntaxUID";
+    }
+    else
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_NotImplemented);
+    }
+  }
 }
diff --git a/Plugins/Samples/Common/DicomTag.h b/Plugins/Samples/Common/DicomTag.h
new file mode 100644
index 0000000..660d078
--- /dev/null
+++ b/Plugins/Samples/Common/DicomTag.h
@@ -0,0 +1,95 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <stdint.h>
+
+namespace OrthancPlugins
+{
+  class DicomTag
+  {
+  private:
+    uint16_t  group_;
+    uint16_t  element_;
+
+    DicomTag();  // Forbidden
+
+  public:
+    DicomTag(uint16_t group,
+             uint16_t element) :
+      group_(group),
+      element_(element)
+    {
+    }
+
+    uint16_t GetGroup() const
+    {
+      return group_;
+    }
+
+    uint16_t GetElement() const
+    {
+      return element_;
+    }
+
+    const char* GetName() const;
+
+    bool operator== (const DicomTag& other) const
+    {
+      return group_ == other.group_ && element_ == other.element_;
+    }
+
+    bool operator!= (const DicomTag& other) const
+    {
+      return !(*this == other);
+    }
+  };
+
+
+  static const DicomTag DICOM_TAG_BITS_STORED(0x0028, 0x0101);
+  static const DicomTag DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021e);
+  static const DicomTag DICOM_TAG_COLUMNS(0x0028, 0x0011);
+  static const DicomTag DICOM_TAG_MODALITY(0x0008, 0x0060);
+  static const DicomTag DICOM_TAG_NUMBER_OF_FRAMES(0x0028, 0x0008);
+  static const DicomTag DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE(0x5200, 0x9230);
+  static const DicomTag DICOM_TAG_PHOTOMETRIC_INTERPRETATION(0x0028, 0x0004);
+  static const DicomTag DICOM_TAG_PIXEL_REPRESENTATION(0x0028, 0x0103);
+  static const DicomTag DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE(0x0048, 0x021a);
+  static const DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f);
+  static const DicomTag DICOM_TAG_ROWS(0x0028, 0x0010);
+  static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016);
+  static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002);
+  static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS(0x0048, 0x0006);
+  static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS(0x0048, 0x0007);
+  static const DicomTag DICOM_TAG_TRANSFER_SYNTAX_UID(0x0002, 0x0010);
+}
diff --git a/Plugins/Samples/Common/FullOrthancDataset.cpp b/Plugins/Samples/Common/FullOrthancDataset.cpp
new file mode 100644
index 0000000..638654b
--- /dev/null
+++ b/Plugins/Samples/Common/FullOrthancDataset.cpp
@@ -0,0 +1,196 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "FullOrthancDataset.h"
+
+#include "OrthancPluginCppWrapper.h"
+
+namespace OrthancPlugins
+{
+  static const Json::Value* AccessTag(const Json::Value& dataset,
+                                      const DicomTag& tag) 
+  {
+    if (dataset.type() != Json::objectValue)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+
+    char name[16];
+    sprintf(name, "%04x,%04x", tag.GetGroup(), tag.GetElement());
+
+    if (!dataset.isMember(name))
+    {
+      return NULL;
+    }
+
+    const Json::Value& value = dataset[name];
+    if (value.type() != Json::objectValue ||
+        !value.isMember("Name") ||
+        !value.isMember("Type") ||
+        !value.isMember("Value") ||
+        value["Name"].type() != Json::stringValue ||
+        value["Type"].type() != Json::stringValue)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+
+    return &value;
+  }
+
+
+  static const Json::Value& GetSequenceContent(const Json::Value& sequence)
+  {
+    assert(sequence.type() == Json::objectValue);
+    assert(sequence.isMember("Type"));
+    assert(sequence.isMember("Value"));
+
+    const Json::Value& value = sequence["Value"];
+      
+    if (sequence["Type"].asString() != "Sequence" ||
+        value.type() != Json::arrayValue)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+    else
+    {
+      return value;
+    }
+  }
+
+
+  static bool GetStringInternal(std::string& result,
+                                const Json::Value& tag)
+  {
+    assert(tag.type() == Json::objectValue);
+    assert(tag.isMember("Type"));
+    assert(tag.isMember("Value"));
+
+    const Json::Value& value = tag["Value"];
+      
+    if (tag["Type"].asString() != "String" ||
+        value.type() != Json::stringValue)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+    else
+    {
+      result = value.asString();
+      return true;
+    }
+  }
+
+
+  const Json::Value* FullOrthancDataset::LookupPath(const DicomPath& path) const
+  {
+    const Json::Value* content = &root_;
+                                  
+    for (unsigned int depth = 0; depth < path.GetPrefixLength(); depth++)
+    {
+      const Json::Value* sequence = AccessTag(*content, path.GetPrefixTag(depth));
+      if (sequence == NULL)
+      {
+        return NULL;
+      }
+
+      const Json::Value& nextContent = GetSequenceContent(*sequence);
+
+      size_t index = path.GetPrefixIndex(depth);
+      if (index >= nextContent.size())
+      {
+        return NULL;
+      }
+      else
+      {
+        content = &nextContent[static_cast<Json::Value::ArrayIndex>(index)];
+      }
+    }
+
+    return AccessTag(*content, path.GetFinalTag());
+  }
+
+
+  void FullOrthancDataset::CheckRoot() const
+  {
+    if (root_.type() != Json::objectValue)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+  }
+
+
+  FullOrthancDataset::FullOrthancDataset(IOrthancConnection& orthanc,
+                                         const std::string& uri)
+  {
+    IOrthancConnection::RestApiGet(root_, orthanc, uri);
+    CheckRoot();
+  }
+
+
+  FullOrthancDataset::FullOrthancDataset(const std::string& content)
+  {
+    IOrthancConnection::ParseJson(root_, content);
+    CheckRoot();
+  }
+
+
+  bool FullOrthancDataset::GetStringValue(std::string& result,
+                                          const DicomPath& path) const
+  {
+    const Json::Value* value = LookupPath(path);
+
+    if (value == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      return GetStringInternal(result, *value);
+    }
+  }
+
+
+  bool FullOrthancDataset::GetSequenceSize(size_t& size,
+                                           const DicomPath& path) const
+  {
+    const Json::Value* sequence = LookupPath(path);
+
+    if (sequence == NULL)
+    {
+      return false;
+    }
+    else
+    {
+      size = GetSequenceContent(*sequence).size();
+      return true;
+    }
+  }
+}
diff --git a/Core/Images/PngReader.h b/Plugins/Samples/Common/FullOrthancDataset.h
similarity index 71%
copy from Core/Images/PngReader.h
copy to Plugins/Samples/Common/FullOrthancDataset.h
index b6ad811..18ab444 100644
--- a/Core/Images/PngReader.h
+++ b/Plugins/Samples/Common/FullOrthancDataset.h
@@ -32,38 +32,32 @@
 
 #pragma once
 
-#include "ImageAccessor.h"
+#include "IOrthancConnection.h"
+#include "IDicomDataset.h"
 
-#include "../Enumerations.h"
+#include <json/value.h>
 
-#include <vector>
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/noncopyable.hpp>
-
-namespace Orthanc
+namespace OrthancPlugins
 {
-  class PngReader : 
-    public ImageAccessor, 
-    public boost::noncopyable
+  class FullOrthancDataset : public IDicomDataset
   {
   private:
-    struct PngRabi;
-
-    std::vector<uint8_t> data_;
+    Json::Value   root_;
 
-    void CheckHeader(const void* header);
+    const Json::Value* LookupPath(const DicomPath& path) const;
 
-    void Read(PngRabi& rabi);
+    void CheckRoot() const;
 
   public:
-    PngReader();
+    FullOrthancDataset(IOrthancConnection& orthanc,
+                       const std::string& uri);
 
-    void ReadFromFile(const std::string& filename);
+    FullOrthancDataset(const std::string& content);
 
-    void ReadFromMemory(const void* buffer,
-                        size_t size);
+    virtual bool GetStringValue(std::string& result,
+                                const DicomPath& path) const;
 
-    void ReadFromMemory(const std::string& buffer);
+    virtual bool GetSequenceSize(size_t& size,
+                                 const DicomPath& path) const;
   };
 }
diff --git a/Core/Images/JpegReader.h b/Plugins/Samples/Common/IDicomDataset.h
similarity index 81%
copy from Core/Images/JpegReader.h
copy to Plugins/Samples/Common/IDicomDataset.h
index 5cb5551..7fc549e 100644
--- a/Core/Images/JpegReader.h
+++ b/Plugins/Samples/Common/IDicomDataset.h
@@ -32,26 +32,24 @@
 
 #pragma once
 
-#include "ImageAccessor.h"
+#include "DicomPath.h"
 
-#include <string>
 #include <boost/noncopyable.hpp>
+#include <string>
 
-namespace Orthanc
+namespace OrthancPlugins
 {
-  class JpegReader : 
-    public ImageAccessor,
-    public boost::noncopyable
+  class IDicomDataset : public boost::noncopyable
   {
-  private:
-    std::string  content_;
-
   public:
-    void ReadFromFile(const std::string& filename);
+    virtual ~IDicomDataset()
+    {
+    }
 
-    void ReadFromMemory(const void* buffer,
-                        size_t size);
+    virtual bool GetStringValue(std::string& result,
+                                const DicomPath& path) const = 0;
 
-    void ReadFromMemory(const std::string& buffer);
+    virtual bool GetSequenceSize(size_t& size,
+                                 const DicomPath& path) const = 0;
   };
 }
diff --git a/Core/DicomFormat/DicomValue.cpp b/Plugins/Samples/Common/IOrthancConnection.cpp
similarity index 54%
copy from Core/DicomFormat/DicomValue.cpp
copy to Plugins/Samples/Common/IOrthancConnection.cpp
index 32a17b5..5a66912 100644
--- a/Core/DicomFormat/DicomValue.cpp
+++ b/Plugins/Samples/Common/IOrthancConnection.cpp
@@ -30,64 +30,54 @@
  **/
 
 
-#include "../PrecompiledHeaders.h"
-#include "DicomValue.h"
+#include "IOrthancConnection.h"
 
-#include "../OrthancException.h"
-#include "../Toolbox.h"
-
-namespace Orthanc
-{
-  DicomValue::DicomValue(const DicomValue& other) : 
-    type_(other.type_),
-    content_(other.content_)
-  {
-  }
+#include "OrthancPluginCppWrapper.h"
 
+#include <json/reader.h>
 
-  DicomValue::DicomValue(const std::string& content,
-                         bool isBinary) :
-    type_(isBinary ? Type_Binary : Type_String),
-    content_(content)
-  {
-  }
-  
-  
-  DicomValue::DicomValue(const char* data,
-                         size_t size,
-                         bool isBinary) :
-    type_(isBinary ? Type_Binary : Type_String)
+namespace OrthancPlugins
+{
+  void IOrthancConnection::ParseJson(Json::Value& result,
+                                     const std::string& content)
   {
-    content_.assign(data, size);
-  }
+    Json::Reader reader;
     
-  
-  const std::string& DicomValue::GetContent() const
-  {
-    if (type_ == Type_Null)
-    {
-      throw OrthancException(ErrorCode_BadParameterType);
-    }
-    else
+    if (!reader.parse(content, result))
     {
-      return content_;
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
     }
   }
 
 
-  DicomValue* DicomValue::Clone() const
+  void IOrthancConnection::RestApiGet(Json::Value& result,
+                                      IOrthancConnection& orthanc,
+                                      const std::string& uri)
   {
-    return new DicomValue(*this);
+    std::string content;
+    orthanc.RestApiGet(content, uri);
+    ParseJson(result, content);
   }
 
-  
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
-  void DicomValue::FormatDataUriScheme(std::string& target,
-                                       const std::string& mime) const
+
+  void IOrthancConnection::RestApiPost(Json::Value& result,
+                                       IOrthancConnection& orthanc,
+                                       const std::string& uri,
+                                       const std::string& body)
   {
-    Toolbox::EncodeBase64(target, GetContent());
-    target.insert(0, "data:" + mime + ";base64,");
+    std::string content;
+    orthanc.RestApiPost(content, uri, body);
+    ParseJson(result, content);
   }
-#endif
 
+
+  void IOrthancConnection::RestApiPut(Json::Value& result,
+                                      IOrthancConnection& orthanc,
+                                      const std::string& uri,
+                                      const std::string& body)
+  {
+    std::string content;
+    orthanc.RestApiPut(content, uri, body);
+    ParseJson(result, content);
+  }
 }
diff --git a/Plugins/Engine/PluginsErrorDictionary.h b/Plugins/Samples/Common/IOrthancConnection.h
similarity index 56%
copy from Plugins/Engine/PluginsErrorDictionary.h
copy to Plugins/Samples/Common/IOrthancConnection.h
index 018156d..f64dd5a 100644
--- a/Plugins/Engine/PluginsErrorDictionary.h
+++ b/Plugins/Samples/Common/IOrthancConnection.h
@@ -32,61 +32,49 @@
 
 #pragma once
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#include "DicomPath.h"
 
-#include "../Include/orthanc/OrthancCPlugin.h"
-#include "../../Core/OrthancException.h"
-#include "SharedLibrary.h"
-
-#include <map>
-#include <string>
 #include <boost/noncopyable.hpp>
-#include <boost/thread/mutex.hpp>
+#include <string>
 #include <json/value.h>
 
-
-namespace Orthanc
+namespace OrthancPlugins
 {
-  class PluginsErrorDictionary : public boost::noncopyable
+  class IOrthancConnection : public boost::noncopyable
   {
-  private:
-    struct Error
+  public:
+    virtual ~IOrthancConnection()
     {
-      std::string  pluginName_;
-      int32_t      pluginCode_;
-      HttpStatus   httpStatus_;
-      std::string  message_;
-    };
-    
-    typedef std::map<int32_t, Error*>  Errors;
+    }
 
-    boost::mutex  mutex_;
-    int32_t  pos_;
-    Errors   errors_;
+    virtual void RestApiGet(std::string& result,
+                            const std::string& uri) = 0;
 
-  public:
-    PluginsErrorDictionary();
+    virtual void RestApiPost(std::string& result,
+                             const std::string& uri,
+                             const std::string& body) = 0;
 
-    ~PluginsErrorDictionary();
+    virtual void RestApiPut(std::string& result,
+                            const std::string& uri,
+                            const std::string& body) = 0;
 
-    OrthancPluginErrorCode  Register(SharedLibrary& library,
-                                     int32_t  pluginCode,
-                                     uint16_t httpStatus,
-                                     const char* message);
+    virtual void RestApiDelete(const std::string& uri) = 0;
 
-    void  LogError(ErrorCode code,
-                   bool ignoreBuiltinErrors);
+    static void ParseJson(Json::Value& result,
+                          const std::string& content);
 
-    void  LogError(OrthancPluginErrorCode code,
-                   bool ignoreBuiltinErrors)
-    {
-      LogError(static_cast<ErrorCode>(code), ignoreBuiltinErrors);
-    }
+    static void RestApiGet(Json::Value& result,
+                           IOrthancConnection& orthanc,
+                           const std::string& uri);
 
-    bool  Format(Json::Value& message,    /* out */
-                 HttpStatus& httpStatus,  /* out */
-                 const OrthancException& exception);
+    static void RestApiPost(Json::Value& result,
+                            IOrthancConnection& orthanc,
+                            const std::string& uri,
+                            const std::string& body);
+
+    static void RestApiPut(Json::Value& result,
+                           IOrthancConnection& orthanc,
+                           const std::string& uri,
+                           const std::string& body);
   };
 }
-
-#endif
diff --git a/Core/Cache/SharedArchive.cpp b/Plugins/Samples/Common/OrthancHttpConnection.cpp
similarity index 50%
copy from Core/Cache/SharedArchive.cpp
copy to Plugins/Samples/Common/OrthancHttpConnection.cpp
index 93303e8..a1f9846 100644
--- a/Core/Cache/SharedArchive.cpp
+++ b/Plugins/Samples/Common/OrthancHttpConnection.cpp
@@ -30,105 +30,78 @@
  **/
 
 
-#include "../PrecompiledHeaders.h"
-#include "SharedArchive.h"
+#include "OrthancHttpConnection.h"
 
-
-#include "../Uuid.h"
-
-
-namespace Orthanc
+namespace OrthancPlugins
 {
-  void SharedArchive::RemoveInternal(const std::string& id)
+  void OrthancHttpConnection::Setup()
   {
-    Archive::iterator it = archive_.find(id);
+    url_ = client_.GetUrl();
 
-    if (it != archive_.end())
-    {
-      delete it->second;
-      archive_.erase(it);
-    }
+    // Don't follow 3xx HTTP (avoid redirections to "unsupported.png" in Orthanc)
+    client_.SetRedirectionFollowed(false);  
   }
 
 
-  SharedArchive::Accessor::Accessor(SharedArchive& that,
-                                    const std::string& id) :
-    lock_(that.mutex_)
+  OrthancHttpConnection::OrthancHttpConnection() :
+    client_(Orthanc::WebServiceParameters(), "")
   {
-    Archive::iterator it = that.archive_.find(id);
-
-    if (it == that.archive_.end())
-    {
-      throw OrthancException(ErrorCode_InexistentItem);
-    }
-    else
-    {
-      that.lru_.MakeMostRecent(id);
-      item_ = it->second;
-    }
+    Setup();
   }
 
 
-  SharedArchive::SharedArchive(size_t maxSize) : 
-    maxSize_(maxSize)
+  OrthancHttpConnection::OrthancHttpConnection(const Orthanc::WebServiceParameters& parameters) :
+    client_(parameters, "")
   {
-    if (maxSize == 0)
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
+    Setup();
   }
 
 
-  SharedArchive::~SharedArchive()
+  void OrthancHttpConnection::RestApiGet(std::string& result,
+                                         const std::string& uri)
   {
-    for (Archive::iterator it = archive_.begin();
-         it != archive_.end(); ++it)
-    {
-      delete it->second;
-    }
+    boost::mutex::scoped_lock lock(mutex_);
+
+    client_.SetMethod(Orthanc::HttpMethod_Get);
+    client_.SetUrl(url_ + uri);
+    client_.ApplyAndThrowException(result);
   }
 
 
-  std::string SharedArchive::Add(IDynamicObject* obj)
+  void OrthancHttpConnection::RestApiPost(std::string& result,
+                                          const std::string& uri,
+                                          const std::string& body)
   {
     boost::mutex::scoped_lock lock(mutex_);
 
-    if (archive_.size() == maxSize_)
-    {
-      // The quota has been reached, remove the oldest element
-      std::string oldest = lru_.RemoveOldest();
-      RemoveInternal(oldest);
-    }
-
-    std::string id = Toolbox::GenerateUuid();
-    RemoveInternal(id);  // Should never be useful because of UUID
-    archive_[id] = obj;
-    lru_.Add(id);
-
-    return id;
+    client_.SetMethod(Orthanc::HttpMethod_Post);
+    client_.SetUrl(url_ + uri);
+    client_.SetBody(body);
+    client_.ApplyAndThrowException(result);
   }
 
 
-  void SharedArchive::Remove(const std::string& id)
+  void OrthancHttpConnection::RestApiPut(std::string& result,
+                                         const std::string& uri,
+                                         const std::string& body)
   {
     boost::mutex::scoped_lock lock(mutex_);
-    RemoveInternal(id);      
-    lru_.Invalidate(id);
+
+    client_.SetMethod(Orthanc::HttpMethod_Put);
+    client_.SetUrl(url_ + uri);
+    client_.SetBody(body);
+    client_.ApplyAndThrowException(result);
   }
 
 
-  void SharedArchive::List(std::list<std::string>& items)
+  void OrthancHttpConnection::RestApiDelete(const std::string& uri)
   {
-    items.clear();
-
     boost::mutex::scoped_lock lock(mutex_);
 
-    for (Archive::const_iterator it = archive_.begin();
-         it != archive_.end(); ++it)
-    {
-      items.push_back(it->first);
-    }
+    std::string result;
+
+    client_.SetMethod(Orthanc::HttpMethod_Delete);
+    client_.SetUrl(url_ + uri);
+    client_.ApplyAndThrowException(result);
   }
 }
-
-
diff --git a/Plugins/Engine/SharedLibrary.h b/Plugins/Samples/Common/OrthancHttpConnection.h
similarity index 61%
copy from Plugins/Engine/SharedLibrary.h
copy to Plugins/Samples/Common/OrthancHttpConnection.h
index 5a7913a..c1e69bd 100644
--- a/Plugins/Engine/SharedLibrary.h
+++ b/Plugins/Samples/Common/OrthancHttpConnection.h
@@ -32,47 +32,44 @@
 
 #pragma once
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#include "IOrthancConnection.h"
 
-#include "../../Core/OrthancException.h"
+#if HAS_ORTHANC_EXCEPTION != 1
+#  error The macro HAS_ORTHANC_EXCEPTION must be set to 1 if using this header
+#endif
 
-#include <boost/noncopyable.hpp>
+#include "../../../Core/HttpClient.h"
 
-#if defined(_WIN32)
-#include <windows.h>
-#endif
+#include <boost/thread/mutex.hpp>
 
-namespace Orthanc
+namespace OrthancPlugins
 {
-  class SharedLibrary : public boost::noncopyable
+  // This class is thread-safe
+  class OrthancHttpConnection : public IOrthancConnection
   {
-  public:
-#if defined(_WIN32)
-    typedef FARPROC FunctionPointer;
-#else
-    typedef void* FunctionPointer;
-#endif
-
   private:
-    std::string path_;
-    void *handle_;
+    boost::mutex         mutex_;
+    Orthanc::HttpClient  client_;
+    std::string          url_;
 
-    FunctionPointer GetFunctionInternal(const std::string& name);
+    void Setup();
 
   public:
-    SharedLibrary(const std::string& path);
+    OrthancHttpConnection();
+
+    OrthancHttpConnection(const Orthanc::WebServiceParameters& parameters);
 
-    ~SharedLibrary();
+    virtual void RestApiGet(std::string& result,
+                            const std::string& uri);
 
-    const std::string& GetPath() const
-    {
-      return path_;
-    }
+    virtual void RestApiPost(std::string& result,
+                             const std::string& uri,
+                             const std::string& body);
 
-    bool HasFunction(const std::string& name);
+    virtual void RestApiPut(std::string& result,
+                            const std::string& uri,
+                            const std::string& body);
 
-    FunctionPointer GetFunction(const std::string& name);
+    virtual void RestApiDelete(const std::string& uri);
   };
 }
-
-#endif
diff --git a/Core/DicomFormat/DicomImageInformation.h b/Plugins/Samples/Common/OrthancPluginConnection.cpp
similarity index 51%
copy from Core/DicomFormat/DicomImageInformation.h
copy to Plugins/Samples/Common/OrthancPluginConnection.cpp
index 568e6e3..fb82353 100644
--- a/Core/DicomFormat/DicomImageInformation.h
+++ b/Plugins/Samples/Common/OrthancPluginConnection.cpp
@@ -30,98 +30,69 @@
  **/
 
 
-#pragma once
+#include "OrthancPluginConnection.h"
 
-#include "DicomMap.h"
+#include "OrthancPluginCppWrapper.h"
 
-#include <stdint.h>
-
-namespace Orthanc
+namespace OrthancPlugins
 {
-  class DicomImageInformation
+  void OrthancPluginConnection::RestApiGet(std::string& result,
+                                           const std::string& uri) 
   {
-  private:
-    unsigned int width_;
-    unsigned int height_;
-    unsigned int samplesPerPixel_;
-    unsigned int numberOfFrames_;
-
-    bool isPlanar_;
-    bool isSigned_;
-    size_t bytesPerValue_;
-
-    unsigned int bitsAllocated_;
-    unsigned int bitsStored_;
-    unsigned int highBit_;
+    OrthancPlugins::MemoryBuffer buffer(context_);
 
-    PhotometricInterpretation  photometric_;
-
-  public:
-    DicomImageInformation(const DicomMap& values);
-
-    unsigned int GetWidth() const
+    if (buffer.RestApiGet(uri, false))
     {
-      return width_;
+      buffer.ToString(result);
     }
-
-    unsigned int GetHeight() const
+    else
     {
-      return height_;
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
     }
+  }
 
-    unsigned int GetNumberOfFrames() const
-    {
-      return numberOfFrames_;
-    }
 
-    unsigned int GetChannelCount() const
-    {
-      return samplesPerPixel_;
-    }
+  void OrthancPluginConnection::RestApiPost(std::string& result,
+                                            const std::string& uri,
+                                            const std::string& body)
+  {
+    OrthancPlugins::MemoryBuffer buffer(context_);
 
-    unsigned int GetBitsStored() const
+    if (buffer.RestApiPost(uri, body.c_str(), body.size(), false))
     {
-      return bitsStored_;
+      buffer.ToString(result);
     }
-
-    size_t GetBytesPerValue() const
+    else
     {
-      return bytesPerValue_;
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
     }
+  }
 
-    bool IsSigned() const
-    {
-      return isSigned_;
-    }
 
-    unsigned int GetBitsAllocated() const
-    {
-      return bitsAllocated_;
-    }
+  void OrthancPluginConnection::RestApiPut(std::string& result,
+                                           const std::string& uri,
+                                           const std::string& body)
+  {
+    OrthancPlugins::MemoryBuffer buffer(context_);
 
-    unsigned int GetHighBit() const
+    if (buffer.RestApiPut(uri, body.c_str(), body.size(), false))
     {
-      return highBit_;
+      buffer.ToString(result);
     }
-
-    bool IsPlanar() const
+    else
     {
-      return isPlanar_;
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
     }
+  }
 
-    unsigned int GetShift() const
-    {
-      return highBit_ + 1 - bitsStored_;
-    }
 
-    PhotometricInterpretation GetPhotometricInterpretation() const
+  void OrthancPluginConnection::RestApiDelete(const std::string& uri)
+  {
+    OrthancPlugins::MemoryBuffer buffer(context_);
+
+    if (!::OrthancPlugins::RestApiDelete(context_, uri, false))
     {
-      return photometric_;
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
     }
-
-    bool ExtractPixelFormat(PixelFormat& format,
-                            bool ignorePhotometricInterpretation) const;
-
-    size_t GetFrameSize() const;
-  };
+  }
 }
diff --git a/Plugins/Engine/SharedLibrary.h b/Plugins/Samples/Common/OrthancPluginConnection.h
similarity index 68%
copy from Plugins/Engine/SharedLibrary.h
copy to Plugins/Samples/Common/OrthancPluginConnection.h
index 5a7913a..f4b06ff 100644
--- a/Plugins/Engine/SharedLibrary.h
+++ b/Plugins/Samples/Common/OrthancPluginConnection.h
@@ -32,47 +32,35 @@
 
 #pragma once
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#include "IOrthancConnection.h"
 
-#include "../../Core/OrthancException.h"
+#include <orthanc/OrthancCPlugin.h>
 
-#include <boost/noncopyable.hpp>
-
-#if defined(_WIN32)
-#include <windows.h>
-#endif
-
-namespace Orthanc
+namespace OrthancPlugins
 {
-  class SharedLibrary : public boost::noncopyable
+  // This class is thread-safe
+  class OrthancPluginConnection : public IOrthancConnection
   {
-  public:
-#if defined(_WIN32)
-    typedef FARPROC FunctionPointer;
-#else
-    typedef void* FunctionPointer;
-#endif
-
   private:
-    std::string path_;
-    void *handle_;
-
-    FunctionPointer GetFunctionInternal(const std::string& name);
+    OrthancPluginContext*   context_;
 
   public:
-    SharedLibrary(const std::string& path);
-
-    ~SharedLibrary();
-
-    const std::string& GetPath() const
+    OrthancPluginConnection(OrthancPluginContext* context) :
+    context_(context)
     {
-      return path_;
     }
 
-    bool HasFunction(const std::string& name);
+    virtual void RestApiGet(std::string& result,
+                            const std::string& uri);
+
+    virtual void RestApiPost(std::string& result,
+                             const std::string& uri,
+                             const std::string& body);
 
-    FunctionPointer GetFunction(const std::string& name);
+    virtual void RestApiPut(std::string& result,
+                            const std::string& uri,
+                            const std::string& body);
+
+    virtual void RestApiDelete(const std::string& uri);
   };
 }
-
-#endif
diff --git a/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp b/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
index 6a7dbc0..b26c512 100644
--- a/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
+++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
@@ -33,13 +33,15 @@
 #include "OrthancPluginCppWrapper.h"
 
 #include <json/reader.h>
+#include <json/writer.h>
 
 
 namespace OrthancPlugins
 {
-  const char* PluginException::GetErrorDescription(OrthancPluginContext* context) const
+  const char* GetErrorDescription(OrthancPluginContext* context,
+                                  OrthancPluginErrorCode code)
   {
-    const char* description = OrthancPluginGetErrorDescription(context, code_);
+    const char* description = OrthancPluginGetErrorDescription(context, code);
     if (description)
     {
       return description;
@@ -50,6 +52,29 @@ namespace OrthancPlugins
     }
   }
 
+  
+#if HAS_ORTHANC_EXCEPTION == 0
+  void PluginException::Check(OrthancPluginErrorCode code)
+  {
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(code);
+    }
+  }
+#endif
+
+
+  void MemoryBuffer::Check(OrthancPluginErrorCode code)
+  {
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      // Prevent using garbage information
+      buffer_.data = NULL;
+      buffer_.size = 0;
+      ORTHANC_PLUGINS_THROW_EXCEPTION(code);
+    }
+  }
+
 
   MemoryBuffer::MemoryBuffer(OrthancPluginContext* context) : 
     context_(context)
@@ -100,7 +125,7 @@ namespace OrthancPlugins
     if (buffer_.data == NULL ||
         buffer_.size == 0)
     {
-      throw PluginException(OrthancPluginErrorCode_InternalError);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
     }
 
     const char* tmp = reinterpret_cast<const char*>(buffer_.data);
@@ -109,7 +134,7 @@ namespace OrthancPlugins
     if (!reader.parse(tmp, tmp + buffer_.size, target))
     {
       OrthancPluginLogError(context_, "Cannot convert some memory buffer to JSON");
-      throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
     }
   }
 
@@ -141,7 +166,7 @@ namespace OrthancPlugins
     }
     else
     {
-      throw PluginException(error);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(error);
     }
   }
 
@@ -175,7 +200,7 @@ namespace OrthancPlugins
     }
     else
     {
-      throw PluginException(error);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(error);
     }
   }
 
@@ -209,16 +234,66 @@ namespace OrthancPlugins
     }
     else
     {
-      throw PluginException(error);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(error);
     }
   }
 
 
-  OrthancString::OrthancString(OrthancPluginContext* context,
-                               char* str) :
-    context_(context),
-    str_(str)
+  bool MemoryBuffer::RestApiPost(const std::string& uri,
+                                 const Json::Value& body,
+                                 bool applyPlugins)
+  {
+    Json::FastWriter writer;
+    return RestApiPost(uri, writer.write(body), applyPlugins);
+  }
+
+
+  bool MemoryBuffer::RestApiPut(const std::string& uri,
+                                const Json::Value& body,
+                                bool applyPlugins)
+  {
+    Json::FastWriter writer;
+    return RestApiPut(uri, writer.write(body), applyPlugins);
+  }
+
+
+  void MemoryBuffer::CreateDicom(const Json::Value& tags,
+                                 OrthancPluginCreateDicomFlags flags)
+  {
+    Clear();
+
+    Json::FastWriter writer;
+    std::string s = writer.write(tags);
+    
+    Check(OrthancPluginCreateDicom(context_, &buffer_, s.c_str(), NULL, flags));
+  }
+
+
+  void MemoryBuffer::ReadFile(const std::string& path)
+  {
+    Clear();
+    Check(OrthancPluginReadFile(context_, &buffer_, path.c_str()));
+  }
+
+
+  void MemoryBuffer::GetDicomQuery(const OrthancPluginWorklistQuery* query)
+  {
+    Clear();
+    Check(OrthancPluginWorklistGetDicomQuery(context_, &buffer_, query));
+  }
+
+
+  void OrthancString::Assign(char* str)
   {
+    if (str == NULL)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
+    }
+    else
+    {
+      Clear();
+      str_ = str;
+    }
   }
 
 
@@ -250,27 +325,40 @@ namespace OrthancPlugins
     if (str_ == NULL)
     {
       OrthancPluginLogError(context_, "Cannot convert an empty memory buffer to JSON");
-      throw PluginException(OrthancPluginErrorCode_InternalError);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
     }
 
     Json::Reader reader;
     if (!reader.parse(str_, target))
     {
       OrthancPluginLogError(context_, "Cannot convert some memory buffer to JSON");
-      throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
     }
   }
+
+  
+  void MemoryBuffer::DicomToJson(Json::Value& target,
+                                 OrthancPluginDicomToJsonFormat format,
+                                 OrthancPluginDicomToJsonFlags flags,
+                                 uint32_t maxStringLength)
+  {
+    OrthancString str(context_);
+    str.Assign(OrthancPluginDicomBufferToJson(context_, GetData(), GetSize(), format, flags, maxStringLength));
+    str.ToJson(target);
+  }
+
   
 
   OrthancConfiguration::OrthancConfiguration(OrthancPluginContext* context) : 
     context_(context)
   {
-    OrthancString str(context, OrthancPluginGetConfiguration(context));
+    OrthancString str(context);
+    str.Assign(OrthancPluginGetConfiguration(context));
 
     if (str.GetContent() == NULL)
     {
       OrthancPluginLogError(context, "Cannot access the Orthanc configuration");
-      throw PluginException(OrthancPluginErrorCode_InternalError);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
     }
 
     str.ToJson(configuration_);
@@ -278,7 +366,7 @@ namespace OrthancPlugins
     if (configuration_.type() != Json::objectValue)
     {
       OrthancPluginLogError(context, "Unable to read the Orthanc configuration");
-      throw PluginException(OrthancPluginErrorCode_InternalError);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
     }
   }
 
@@ -287,7 +375,7 @@ namespace OrthancPlugins
   {
     if (context_ == NULL)
     {
-      throw PluginException(OrthancPluginErrorCode_Plugin);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_Plugin);
     }
     else
     {
@@ -309,6 +397,15 @@ namespace OrthancPlugins
   }
 
 
+  bool OrthancConfiguration::IsSection(const std::string& key) const
+  {
+    assert(configuration_.type() == Json::objectValue);
+
+    return (configuration_.isMember(key) &&
+            configuration_[key].type() == Json::objectValue);
+  }
+
+
   void OrthancConfiguration::GetSection(OrthancConfiguration& target,
                                         const std::string& key) const
   {
@@ -331,7 +428,7 @@ namespace OrthancPlugins
           OrthancPluginLogError(context_, s.c_str());
         }
 
-        throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+        ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
       }
 
       target.configuration_ = configuration_[key];
@@ -357,7 +454,7 @@ namespace OrthancPlugins
         OrthancPluginLogError(context_, s.c_str());
       }
 
-      throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
     }
 
     target = configuration_[key].asString();
@@ -392,7 +489,7 @@ namespace OrthancPlugins
           OrthancPluginLogError(context_, s.c_str());
         }
 
-        throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+        ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
     }
   }
 
@@ -414,7 +511,7 @@ namespace OrthancPlugins
         OrthancPluginLogError(context_, s.c_str());
       }
 
-      throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
     }
     else
     {
@@ -442,7 +539,7 @@ namespace OrthancPlugins
         OrthancPluginLogError(context_, s.c_str());
       }
 
-      throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
     }
 
     target = configuration_[key].asBool();
@@ -467,11 +564,11 @@ namespace OrthancPlugins
         return true;
         
       case Json::intValue:
-        target = configuration_[key].asInt();
+        target = static_cast<float>(configuration_[key].asInt());
         return true;
         
       case Json::uintValue:
-        target = configuration_[key].asUInt();
+        target = static_cast<float>(configuration_[key].asUInt());
         return true;
         
       default:
@@ -481,7 +578,7 @@ namespace OrthancPlugins
           OrthancPluginLogError(context_, s.c_str());
         }
 
-        throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+        ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
     }
   }
 
@@ -576,7 +673,7 @@ namespace OrthancPlugins
     if (image_ == NULL)
     {
       OrthancPluginLogError(context_, "Trying to access a NULL image");
-      throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
     }
   }
 
@@ -587,7 +684,7 @@ namespace OrthancPlugins
   {
     if (context == NULL)
     {
-      throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
     }
   }
 
@@ -599,7 +696,7 @@ namespace OrthancPlugins
   {
     if (context == NULL)
     {
-      throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
     }
   }
   
@@ -612,7 +709,7 @@ namespace OrthancPlugins
   {
     if (context == NULL)
     {
-      throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
     }
     else
     {
@@ -629,7 +726,7 @@ namespace OrthancPlugins
     if (image_ == NULL)
     {
       OrthancPluginLogError(context_, "Cannot uncompress a PNG image");
-      throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
     }
   }
 
@@ -642,7 +739,7 @@ namespace OrthancPlugins
     if (image_ == NULL)
     {
       OrthancPluginLogError(context_, "Cannot uncompress a JPEG image");
-      throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
     }
   }
 
@@ -656,7 +753,7 @@ namespace OrthancPlugins
     if (image_ == NULL)
     {
       OrthancPluginLogError(context_, "Cannot uncompress a DICOM image");
-      throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
     }
   }
 
@@ -738,10 +835,84 @@ namespace OrthancPlugins
   }
 
 
-  bool RestApiGetJson(Json::Value& result,
-                      OrthancPluginContext* context,
-                      const std::string& uri,
-                      bool applyPlugins)
+  FindMatcher::FindMatcher(OrthancPluginContext*              context,
+                           const OrthancPluginWorklistQuery*  worklist) :
+    context_(context),
+    matcher_(NULL),
+    worklist_(worklist)
+  {
+    if (worklist_ == NULL)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
+  void FindMatcher::SetupDicom(OrthancPluginContext*  context,
+                               const void*            query,
+                               uint32_t               size)
+  {
+    context_ = context;
+    worklist_ = NULL;
+
+    matcher_ = OrthancPluginCreateFindMatcher(context_, query, size);
+    if (matcher_ == NULL)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
+    }
+  }
+
+
+  FindMatcher::~FindMatcher()
+  {
+    // The "worklist_" field 
+
+    if (matcher_ != NULL)
+    {
+      OrthancPluginFreeFindMatcher(context_, matcher_);
+    }
+  }
+
+
+
+  bool FindMatcher::IsMatch(const void*  dicom,
+                            uint32_t     size) const
+  {
+    int32_t result;
+
+    if (matcher_ != NULL)
+    {
+      result = OrthancPluginFindMatcherIsMatch(context_, matcher_, dicom, size);
+    }
+    else if (worklist_ != NULL)
+    {
+      result = OrthancPluginWorklistIsMatch(context_, worklist_, dicom, size);
+    }
+    else
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
+    }
+
+    if (result == 0)
+    {
+      return false;
+    }
+    else if (result == 1)
+    {
+      return true;
+    }
+    else
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
+    }
+  }
+
+
+
+  bool RestApiGet(Json::Value& result,
+                  OrthancPluginContext* context,
+                  const std::string& uri,
+                  bool applyPlugins)
   {
     MemoryBuffer answer(context);
     if (!answer.RestApiGet(uri, applyPlugins))
@@ -756,12 +927,12 @@ namespace OrthancPlugins
   }
 
 
-  bool RestApiPostJson(Json::Value& result,
-                       OrthancPluginContext* context,
-                       const std::string& uri,
-                       const char* body,
-                       size_t bodySize,
-                       bool applyPlugins)
+  bool RestApiPost(Json::Value& result,
+                   OrthancPluginContext* context,
+                   const std::string& uri,
+                   const char* body,
+                   size_t bodySize,
+                   bool applyPlugins)
   {
     MemoryBuffer answer(context);
     if (!answer.RestApiPost(uri, body, bodySize, applyPlugins))
@@ -776,12 +947,23 @@ namespace OrthancPlugins
   }
 
 
-  bool RestApiPutJson(Json::Value& result,
-                      OrthancPluginContext* context,
-                      const std::string& uri,
-                      const char* body,
-                      size_t bodySize,
-                      bool applyPlugins)
+  bool RestApiPost(Json::Value& result,
+                   OrthancPluginContext* context,
+                   const std::string& uri,
+                   const Json::Value& body,
+                   bool applyPlugins)
+  {
+    Json::FastWriter writer;
+    return RestApiPost(result, context, uri, writer.write(body), applyPlugins);
+  }
+
+
+  bool RestApiPut(Json::Value& result,
+                  OrthancPluginContext* context,
+                  const std::string& uri,
+                  const char* body,
+                  size_t bodySize,
+                  bool applyPlugins)
   {
     MemoryBuffer answer(context);
     if (!answer.RestApiPut(uri, body, bodySize, applyPlugins))
@@ -796,6 +978,17 @@ namespace OrthancPlugins
   }
 
 
+  bool RestApiPut(Json::Value& result,
+                   OrthancPluginContext* context,
+                   const std::string& uri,
+                   const Json::Value& body,
+                   bool applyPlugins)
+  {
+    Json::FastWriter writer;
+    return RestApiPut(result, context, uri, writer.write(body), applyPlugins);
+  }
+
+
   bool RestApiDelete(OrthancPluginContext* context,
                      const std::string& uri,
                      bool applyPlugins)
@@ -822,7 +1015,99 @@ namespace OrthancPlugins
     }
     else
     {
-      throw PluginException(error);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(error);
+    }
+  }
+
+
+  static void ReportIncompatibleVersion(OrthancPluginContext* context,
+                                        unsigned int major,
+                                        unsigned int minor,
+                                        unsigned int revision)
+  {
+    char buf[128];
+    sprintf(buf, "Your version of the Orthanc core (%s) is too old to run this plugin (%d.%d.%d is required)",
+            context->orthancVersion, major, minor, revision);
+    OrthancPluginLogError(context, buf);
+  }
+
+
+  bool CheckMinimalOrthancVersion(OrthancPluginContext* context,
+                                  unsigned int major,
+                                  unsigned int minor,
+                                  unsigned int revision)
+  {
+    if (context == NULL)
+    {
+      OrthancPluginLogError(context, "Bad Orthanc context in the plugin");      
+      return false;
+    }
+
+    if (!strcmp(context->orthancVersion, "mainline"))
+    {
+      // Assume compatibility with the mainline
+      return true;
+    }
+
+    // Parse the version of the Orthanc core
+    int aa, bb, cc;
+    if ( 
+#ifdef _MSC_VER
+      sscanf_s
+#else
+      sscanf
+#endif
+      (context->orthancVersion, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 ||
+      aa < 0 ||
+      bb < 0 ||
+      cc < 0)
+    {
+      throw false;
+    }
+
+    unsigned int a = static_cast<unsigned int>(aa);
+    unsigned int b = static_cast<unsigned int>(bb);
+    unsigned int c = static_cast<unsigned int>(cc);
+
+    // Check the major version number
+
+    if (a > major)
+    {
+      return true;
+    }
+
+    if (a < major)
+    {
+      ReportIncompatibleVersion(context, major, minor, revision);
+      return false;
+    }
+
+
+    // Check the minor version number
+    assert(a == major);
+
+    if (b > minor)
+    {
+      return true;
+    }
+
+    if (b < minor)
+    {
+      ReportIncompatibleVersion(context, major, minor, revision);
+      return false;
+    }
+
+    // Check the patch level version number
+    assert(a == major && b == minor);
+
+    if (c >= revision)
+    {
+      return true;
+    }
+    else
+    {
+      ReportIncompatibleVersion(context, major, minor, revision);
+      return false;
     }
   }
 }
diff --git a/Plugins/Samples/Common/OrthancPluginCppWrapper.h b/Plugins/Samples/Common/OrthancPluginCppWrapper.h
index 2b9966f..bbb69e8 100644
--- a/Plugins/Samples/Common/OrthancPluginCppWrapper.h
+++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.h
@@ -37,18 +37,30 @@
 #include <boost/lexical_cast.hpp>
 #include <json/value.h>
 
+#if !defined(HAS_ORTHANC_EXCEPTION)
+#  error The macro HAS_ORTHANC_EXCEPTION must be defined
+#endif
+
+
 #if HAS_ORTHANC_EXCEPTION == 1
-#  include <OrthancException.h>
+#  include "../../../Core/OrthancException.h"
+#  define ORTHANC_PLUGINS_THROW_EXCEPTION(code)  throw ::Orthanc::OrthancException(static_cast<Orthanc::ErrorCode>(code))
+#else
+#  define ORTHANC_PLUGINS_THROW_EXCEPTION(code)  throw ::OrthancPlugins::PluginException(code)
 #endif
 
 
+
 namespace OrthancPlugins
 {
   typedef void (*RestCallback) (OrthancPluginRestOutput* output,
                                 const char* url,
                                 const OrthancPluginHttpRequest* request);
 
+  const char* GetErrorDescription(OrthancPluginContext* context,
+                                  OrthancPluginErrorCode code);
 
+#if HAS_ORTHANC_EXCEPTION == 0
   class PluginException
   {
   private:
@@ -64,8 +76,14 @@ namespace OrthancPlugins
       return code_;
     }
 
-    const char* GetErrorDescription(OrthancPluginContext* context) const;
+    const char* What(OrthancPluginContext* context) const
+    {
+      return ::OrthancPlugins::GetErrorDescription(context, code_);
+    }
+
+    static void Check(OrthancPluginErrorCode code);
   };
+#endif
 
 
   class MemoryBuffer : public boost::noncopyable
@@ -74,6 +92,8 @@ namespace OrthancPlugins
     OrthancPluginContext*      context_;
     OrthancPluginMemoryBuffer  buffer_;
 
+    void Check(OrthancPluginErrorCode code);
+
   public:
     MemoryBuffer(OrthancPluginContext* context);
 
@@ -127,6 +147,14 @@ namespace OrthancPlugins
                     bool applyPlugins);
 
     bool RestApiPost(const std::string& uri,
+                     const Json::Value& body,
+                     bool applyPlugins);
+
+    bool RestApiPut(const std::string& uri,
+                    const Json::Value& body,
+                    bool applyPlugins);
+
+    bool RestApiPost(const std::string& uri,
                      const std::string& body,
                      bool applyPlugins)
     {
@@ -139,6 +167,18 @@ namespace OrthancPlugins
     {
       return RestApiPut(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins);
     }
+
+    void CreateDicom(const Json::Value& tags,
+                     OrthancPluginCreateDicomFlags flags);
+
+    void ReadFile(const std::string& path);
+
+    void GetDicomQuery(const OrthancPluginWorklistQuery* query);
+
+    void DicomToJson(Json::Value& target,
+                     OrthancPluginDicomToJsonFormat format,
+                     OrthancPluginDicomToJsonFlags flags,
+                     uint32_t maxStringLength);
   };
 
 
@@ -148,16 +188,23 @@ namespace OrthancPlugins
     OrthancPluginContext*  context_;
     char*                  str_;
 
+    void Clear();
+
   public:
-    OrthancString(OrthancPluginContext* context,
-                  char* str);
+    OrthancString(OrthancPluginContext* context) :
+      context_(context),
+      str_(NULL)
+    {
+    }
 
     ~OrthancString()
     {
       Clear();
     }
 
-    void Clear();
+    // This transfers ownership, warning: The string must have been
+    // allocated by the Orthanc core
+    void Assign(char* str);
 
     const char* GetContent() const
     {
@@ -174,7 +221,7 @@ namespace OrthancPlugins
   {
   private:
     OrthancPluginContext*  context_;
-    Json::Value            configuration_;
+    Json::Value            configuration_;  // Necessarily a Json::objectValue
     std::string            path_;
 
     std::string GetPath(const std::string& key) const;
@@ -193,6 +240,8 @@ namespace OrthancPlugins
       return configuration_;
     }
 
+    bool IsSection(const std::string& key) const;
+
     void GetSection(OrthancConfiguration& target,
                     const std::string& key) const;
 
@@ -227,7 +276,7 @@ namespace OrthancPlugins
                         float defaultValue) const;
   };
 
-  class OrthancImage
+  class OrthancImage : public boost::noncopyable
   {
   private:
     OrthancPluginContext*  context_;
@@ -285,52 +334,132 @@ namespace OrthancPlugins
   };
 
 
-  bool RestApiGetJson(Json::Value& result,
-                      OrthancPluginContext* context,
-                      const std::string& uri,
-                      bool applyPlugins);
-
-  bool RestApiPostJson(Json::Value& result,
-                       OrthancPluginContext* context,
-                       const std::string& uri,
-                       const char* body,
-                       size_t bodySize,
-                       bool applyPlugins);
-
-  bool RestApiPutJson(Json::Value& result,
-                      OrthancPluginContext* context,
-                      const std::string& uri,
-                      const char* body,
-                      size_t bodySize,
-                      bool applyPlugins);
-
-  inline bool RestApiPostJson(Json::Value& result,
-                              OrthancPluginContext* context,
-                              const std::string& uri,
-                              const std::string& body,
-                              bool applyPlugins)
+  class FindMatcher : public boost::noncopyable
+  {
+  private:
+    OrthancPluginContext*              context_;
+    OrthancPluginFindMatcher*          matcher_;
+    const OrthancPluginWorklistQuery*  worklist_;
+
+    void SetupDicom(OrthancPluginContext*  context,
+                    const void*            query,
+                    uint32_t               size);
+
+  public:
+    FindMatcher(OrthancPluginContext*              context,
+                const OrthancPluginWorklistQuery*  worklist);
+
+    FindMatcher(OrthancPluginContext*  context,
+                const void*            query,
+                uint32_t               size)
+    {
+      SetupDicom(context, query, size);
+    }
+
+    FindMatcher(OrthancPluginContext*  context,
+                const MemoryBuffer&    dicom)
+    {
+      SetupDicom(context, dicom.GetData(), dicom.GetSize());
+    }
+
+    ~FindMatcher();
+
+    bool IsMatch(const void*  dicom,
+                 uint32_t     size) const;
+
+    bool IsMatch(const MemoryBuffer& dicom) const
+    {
+      return IsMatch(dicom.GetData(), dicom.GetSize());
+    }
+  };
+
+
+  bool RestApiGet(Json::Value& result,
+                  OrthancPluginContext* context,
+                  const std::string& uri,
+                  bool applyPlugins);
+
+  bool RestApiPost(Json::Value& result,
+                   OrthancPluginContext* context,
+                   const std::string& uri,
+                   const char* body,
+                   size_t bodySize,
+                   bool applyPlugins);
+
+  bool RestApiPost(Json::Value& result,
+                   OrthancPluginContext* context,
+                   const std::string& uri,
+                   const Json::Value& body,
+                   bool applyPlugins);
+
+  inline bool RestApiPost(Json::Value& result,
+                          OrthancPluginContext* context,
+                          const std::string& uri,
+                          const std::string& body,
+                          bool applyPlugins)
   {
-    return RestApiPostJson(result, context, uri, body.empty() ? NULL : body.c_str(), 
-                           body.size(), applyPlugins);
+    return RestApiPost(result, context, uri, body.empty() ? NULL : body.c_str(), 
+                       body.size(), applyPlugins);
+  }
+
+  bool RestApiPut(Json::Value& result,
+                  OrthancPluginContext* context,
+                  const std::string& uri,
+                  const char* body,
+                  size_t bodySize,
+                  bool applyPlugins);
+
+  bool RestApiPut(Json::Value& result,
+                  OrthancPluginContext* context,
+                  const std::string& uri,
+                  const Json::Value& body,
+                  bool applyPlugins);
+
+  inline bool RestApiPut(Json::Value& result,
+                         OrthancPluginContext* context,
+                         const std::string& uri,
+                         const std::string& body,
+                         bool applyPlugins)
+  {
+    return RestApiPut(result, context, uri, body.empty() ? NULL : body.c_str(), 
+                      body.size(), applyPlugins);
   }
 
   bool RestApiDelete(OrthancPluginContext* context,
                      const std::string& uri,
                      bool applyPlugins);
 
-  inline bool RestApiPutJson(Json::Value& result,
-                             OrthancPluginContext* context,
-                             const std::string& uri,
-                             const std::string& body,
-                             bool applyPlugins)
+  inline void LogError(OrthancPluginContext* context,
+                       const std::string& message)
   {
-    return RestApiPutJson(result, context, uri, body.empty() ? NULL : body.c_str(), 
-                          body.size(), applyPlugins);
+    if (context != NULL)
+    {
+      OrthancPluginLogError(context, message.c_str());
+    }
   }
 
-  bool RestApiDelete(OrthancPluginContext* context,
-                     const std::string& uri,
-                     bool applyPlugins);
+  inline void LogWarning(OrthancPluginContext* context,
+                         const std::string& message)
+  {
+    if (context != NULL)
+    {
+      OrthancPluginLogWarning(context, message.c_str());
+    }
+  }
+
+  inline void LogInfo(OrthancPluginContext* context,
+                      const std::string& message)
+  {
+    if (context != NULL)
+    {
+      OrthancPluginLogInfo(context, message.c_str());
+    }
+  }
+
+  bool CheckMinimalOrthancVersion(OrthancPluginContext* context,
+                                  unsigned int major,
+                                  unsigned int minor,
+                                  unsigned int revision);
 
 
   namespace Internals
@@ -345,17 +474,18 @@ namespace OrthancPlugins
         Callback(output, url, request);
         return OrthancPluginErrorCode_Success;
       }
-      catch (OrthancPlugins::PluginException& e)
-      {
-        return e.GetErrorCode();
-      }
 #if HAS_ORTHANC_EXCEPTION == 1
       catch (Orthanc::OrthancException& e)
       {
         return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
       }
+#else
+      catch (OrthancPlugins::PluginException& e)
+      {
+        return e.GetErrorCode();
+      }
 #endif
-      catch (boost::bad_lexical_cast& e)
+      catch (boost::bad_lexical_cast&)
       {
         return OrthancPluginErrorCode_BadFileFormat;
       }
diff --git a/Plugins/Samples/Common/OrthancPlugins.cmake b/Plugins/Samples/Common/OrthancPlugins.cmake
index d7228a1..90f5224 100644
--- a/Plugins/Samples/Common/OrthancPlugins.cmake
+++ b/Plugins/Samples/Common/OrthancPlugins.cmake
@@ -17,7 +17,7 @@ endif()
 if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
   # Linking with "pthread" is necessary, otherwise the software crashes
   # http://sourceware.org/bugzilla/show_bug.cgi?id=10652#c17
-  link_libraries(dl rt)
+  link_libraries(dl rt pthread)
 endif()
 
 
@@ -27,3 +27,6 @@ include_directories(${SAMPLES_ROOT}/../Include/)
 if (MSVC)
   include_directories(${SAMPLES_ROOT}/../../Resources/ThirdParty/VisualStudio/)
 endif()
+
+
+add_definitions(-DHAS_ORTHANC_EXCEPTION=0)
diff --git a/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp b/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp
new file mode 100644
index 0000000..1fa2bea
--- /dev/null
+++ b/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp
@@ -0,0 +1,156 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "SimplifiedOrthancDataset.h"
+
+#include "OrthancPluginCppWrapper.h"
+
+namespace OrthancPlugins
+{
+  const Json::Value* SimplifiedOrthancDataset::LookupPath(const DicomPath& path) const
+  {
+    const Json::Value* content = &root_;
+                                  
+    for (unsigned int depth = 0; depth < path.GetPrefixLength(); depth++)
+    {
+      const char* name = path.GetPrefixTag(depth).GetName();
+      if (content->type() != Json::objectValue)
+      {
+        ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+      }
+
+      if (!content->isMember(name))
+      {
+        return NULL;
+      }
+
+      const Json::Value& sequence = (*content) [name];
+      if (sequence.type() != Json::arrayValue)
+      {
+        ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+      }
+
+      size_t index = path.GetPrefixIndex(depth);
+      if (index >= sequence.size())
+      {
+        return NULL;
+      }
+      else
+      {
+        content = &sequence[static_cast<Json::Value::ArrayIndex>(index)];
+      }
+    }
+
+    const char* name = path.GetFinalTag().GetName();
+
+    if (content->type() != Json::objectValue)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+    if (!content->isMember(name))
+    {
+      return NULL;
+    }
+    else
+    {
+      return &((*content) [name]);
+    }
+  }
+
+
+  void SimplifiedOrthancDataset::CheckRoot() const
+  {
+    if (root_.type() != Json::objectValue)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+  }
+
+
+  SimplifiedOrthancDataset::SimplifiedOrthancDataset(IOrthancConnection& orthanc,
+                                                     const std::string& uri)
+  {
+    IOrthancConnection::RestApiGet(root_, orthanc, uri);
+    CheckRoot();
+  }
+
+
+  SimplifiedOrthancDataset::SimplifiedOrthancDataset(const std::string& content)
+  {
+    IOrthancConnection::ParseJson(root_, content);
+    CheckRoot();
+  }
+
+
+  bool SimplifiedOrthancDataset::GetStringValue(std::string& result,
+                                                const DicomPath& path) const
+  {
+    const Json::Value* value = LookupPath(path);
+
+    if (value == NULL)
+    {
+      return false;
+    }
+    else if (value->type() != Json::stringValue)
+    {
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+    else
+    {
+      result = value->asString();
+      return true;
+    }
+  }
+
+
+  bool SimplifiedOrthancDataset::GetSequenceSize(size_t& size,
+                                                 const DicomPath& path) const
+  {
+    const Json::Value* sequence = LookupPath(path);
+
+    if (sequence == NULL)
+    {
+      // Inexistent path
+      return false;
+    }
+    else if (sequence->type() != Json::arrayValue)
+    {
+      // Not a sequence
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+    else
+    {
+      size = sequence->size();
+      return true;
+    }
+  }
+}
diff --git a/Core/Images/PngReader.h b/Plugins/Samples/Common/SimplifiedOrthancDataset.h
similarity index 71%
copy from Core/Images/PngReader.h
copy to Plugins/Samples/Common/SimplifiedOrthancDataset.h
index b6ad811..a71e1e0 100644
--- a/Core/Images/PngReader.h
+++ b/Plugins/Samples/Common/SimplifiedOrthancDataset.h
@@ -32,38 +32,30 @@
 
 #pragma once
 
-#include "ImageAccessor.h"
+#include "IOrthancConnection.h"
+#include "IDicomDataset.h"
 
-#include "../Enumerations.h"
-
-#include <vector>
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/noncopyable.hpp>
-
-namespace Orthanc
+namespace OrthancPlugins
 {
-  class PngReader : 
-    public ImageAccessor, 
-    public boost::noncopyable
+  class SimplifiedOrthancDataset : public IDicomDataset
   {
   private:
-    struct PngRabi;
-
-    std::vector<uint8_t> data_;
+    Json::Value   root_;
 
-    void CheckHeader(const void* header);
+    const Json::Value* LookupPath(const DicomPath& path) const;
 
-    void Read(PngRabi& rabi);
+    void CheckRoot() const;
 
   public:
-    PngReader();
+    SimplifiedOrthancDataset(IOrthancConnection& orthanc,
+                             const std::string& uri);
 
-    void ReadFromFile(const std::string& filename);
+    SimplifiedOrthancDataset(const std::string& content);
 
-    void ReadFromMemory(const void* buffer,
-                        size_t size);
+    virtual bool GetStringValue(std::string& result,
+                                const DicomPath& path) const;
 
-    void ReadFromMemory(const std::string& buffer);
+    virtual bool GetSequenceSize(size_t& size,
+                                 const DicomPath& path) const;
   };
 }
diff --git a/Plugins/Samples/DatabasePlugin/CMakeLists.txt b/Plugins/Samples/DatabasePlugin/CMakeLists.txt
index be977d0..11c6cfd 100644
--- a/Plugins/Samples/DatabasePlugin/CMakeLists.txt
+++ b/Plugins/Samples/DatabasePlugin/CMakeLists.txt
@@ -29,11 +29,12 @@ message("Setting the version of the plugin to ${SAMPLE_DATABASE_VERSION}")
 
 add_definitions(
   -DORTHANC_SQLITE_STANDALONE=1
-  -DORTHANC_ENABLE_LOGGING=0
   -DORTHANC_ENABLE_BASE64=0
+  -DORTHANC_ENABLE_LOGGING=0
   -DORTHANC_ENABLE_MD5=0
-  -DORTHANC_ENABLE_DCMTK=0
-  -DORTHANC_PLUGINS_ENABLED=1
+  -DORTHANC_ENABLE_PLUGINS=1
+  -DORTHANC_ENABLE_PUGIXML=0
+  -DORTHANC_SANDBOXED=0
   -DSAMPLE_DATABASE_VERSION="${SAMPLE_DATABASE_VERSION}"
   )
 
diff --git a/Plugins/Samples/ModalityWorklists/CMakeLists.txt b/Plugins/Samples/ModalityWorklists/CMakeLists.txt
index eee38f1..fcf6606 100644
--- a/Plugins/Samples/ModalityWorklists/CMakeLists.txt
+++ b/Plugins/Samples/ModalityWorklists/CMakeLists.txt
@@ -16,6 +16,7 @@ include(${ORTHANC_ROOT}/Resources/CMake/BoostConfiguration.cmake)
 
 add_library(ModalityWorklists SHARED 
   Plugin.cpp
+  ../Common/OrthancPluginCppWrapper.cpp
   ${JSONCPP_SOURCES}
   ${BOOST_SOURCES}
   )
diff --git a/Plugins/Samples/ModalityWorklists/Plugin.cpp b/Plugins/Samples/ModalityWorklists/Plugin.cpp
index f68fc29..8aebfa8 100644
--- a/Plugins/Samples/ModalityWorklists/Plugin.cpp
+++ b/Plugins/Samples/ModalityWorklists/Plugin.cpp
@@ -18,7 +18,7 @@
  **/
 
 
-#include <orthanc/OrthancCPlugin.h>
+#include "../Common/OrthancPluginCppWrapper.h"
 
 #include <boost/filesystem.hpp>
 #include <json/value.h>
@@ -31,92 +31,99 @@ static OrthancPluginContext* context_ = NULL;
 static std::string folder_;
 
 
-static bool ReadFile(std::string& result,
-                     const std::string& path)
-{
-  OrthancPluginMemoryBuffer tmp;
-  if (OrthancPluginReadFile(context_, &tmp, path.c_str()))
-  {
-    return false;
-  }
-  else
-  {
-    result.assign(reinterpret_cast<const char*>(tmp.data), tmp.size);
-    OrthancPluginFreeMemoryBuffer(context_, &tmp);
-    return true;
-  }
-}
-
-
 /**
  * This is the main function for matching a DICOM worklist against a query.
  **/
-static OrthancPluginErrorCode  MatchWorklist(OrthancPluginWorklistAnswers*     answers,
-                                             const OrthancPluginWorklistQuery* query,
-                                             const std::string& path)
+static void  MatchWorklist(OrthancPluginWorklistAnswers*      answers,
+                           const OrthancPluginWorklistQuery*  query,
+                           const OrthancPlugins::FindMatcher& matcher,
+                           const std::string& path)
 {
-  std::string dicom;
-  if (!ReadFile(dicom, path))
-  {
-    // Cannot read this file, ignore this error
-    return OrthancPluginErrorCode_Success;
-  }
+  OrthancPlugins::MemoryBuffer dicom(context_);
+  dicom.ReadFile(path);
 
-  if (OrthancPluginWorklistIsMatch(context_, query, dicom.c_str(), dicom.size()))
+  if (matcher.IsMatch(dicom))
   {
     // This DICOM file matches the worklist query, add it to the answers
-    return OrthancPluginWorklistAddAnswer
-      (context_, answers, query, dicom.c_str(), dicom.size());
-  }
-  else
-  {
-    // This DICOM file does not match
-    return OrthancPluginErrorCode_Success;
+    OrthancPluginErrorCode code = OrthancPluginWorklistAddAnswer
+      (context_, answers, query, dicom.GetData(), dicom.GetSize());
+
+    if (code != OrthancPluginErrorCode_Success)
+    {
+      OrthancPlugins::LogError(context_, "Error while adding an answer to a worklist request");
+      ORTHANC_PLUGINS_THROW_EXCEPTION(code);
+    }
   }
 }
 
 
-
-static bool ConvertToJson(Json::Value& result,
-                          char* content)
+static OrthancPlugins::FindMatcher* CreateMatcher(const OrthancPluginWorklistQuery* query,
+                                                  const char*                       remoteAet)
 {
-  if (content == NULL)
+  // Extract the DICOM instance underlying the C-Find query
+  OrthancPlugins::MemoryBuffer dicom(context_);
+  dicom.GetDicomQuery(query);
+
+  // Convert the DICOM as JSON, and dump it to the user in "--verbose" mode
+  Json::Value json;
+  dicom.DicomToJson(json, OrthancPluginDicomToJsonFormat_Short, 
+                    static_cast<OrthancPluginDicomToJsonFlags>(0), 0);
+  
+  OrthancPlugins::LogInfo(context_, "Received worklist query from remote modality " + 
+                          std::string(remoteAet) + ":\n" + json.toStyledString());
+
+#if 1
+  return new OrthancPlugins::FindMatcher(context_, query);
+
+#else
+  // Alternative sample showing how to fine-tune an incoming C-Find
+  // request, before matching it against the worklist database. The
+  // code below will restrict the original DICOM request by requesting
+  // the ScheduledStationAETitle to correspond to the AET of the
+  // issuer. This code will make the integration test "test_other_aet"
+  // succeed (cf. the orthanc-tests repository).
+
+  static const char* SCHEDULED_PROCEDURE_STEP_SEQUENCE = "0040,0100";
+  static const char* SCHEDULED_STATION_AETITLE = "0040,0001";
+
+  if (!json.isMember(SCHEDULED_PROCEDURE_STEP_SEQUENCE))
   {
-    return false;
+    // Create a ScheduledProcedureStepSequence sequence, with one empty element
+    json[SCHEDULED_PROCEDURE_STEP_SEQUENCE] = Json::arrayValue;
+    json[SCHEDULED_PROCEDURE_STEP_SEQUENCE].append(Json::objectValue);
   }
-  else
+
+  Json::Value& v = json[SCHEDULED_PROCEDURE_STEP_SEQUENCE];
+
+  if (v.type() != Json::arrayValue ||
+      v.size() != 1 ||
+      v[0].type() != Json::objectValue)
   {
-    Json::Reader reader;
-    bool success = reader.parse(content, content + strlen(content), result);
-    OrthancPluginFreeString(context_, content);
-    return success;
+    ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
   }
-}
 
-
-static bool GetQueryDicom(Json::Value& value,
-                          const OrthancPluginWorklistQuery* query)
-{
-  OrthancPluginMemoryBuffer dicom;
-  if (OrthancPluginWorklistGetDicomQuery(context_, &dicom, query))
+  // Set the ScheduledStationAETitle if none was provided
+  if (!v[0].isMember(SCHEDULED_STATION_AETITLE) ||
+      v[0].type() != Json::stringValue ||
+      v[0][SCHEDULED_STATION_AETITLE].asString().size() == 0 ||
+      v[0][SCHEDULED_STATION_AETITLE].asString() == "*")
   {
-    return false;
+    v[0][SCHEDULED_STATION_AETITLE] = remoteAet;
   }
 
-  char* json = OrthancPluginDicomBufferToJson(context_, reinterpret_cast<const char*>(dicom.data),
-                                              dicom.size, 
-                                              OrthancPluginDicomToJsonFormat_Short, 
-                                              static_cast<OrthancPluginDicomToJsonFlags>(0), 0);
-  OrthancPluginFreeMemoryBuffer(context_, &dicom);
+  if (json.isMember("0010,21c0") &&
+      json["0010,21c0"].asString().size() == 0)
+  {
+    json.removeMember("0010,21c0");
+  }
 
-  return ConvertToJson(value, json);
+  // Encode the modified JSON as a DICOM instance, then convert it to a C-Find matcher
+  OrthancPlugins::MemoryBuffer modified(context_);
+  modified.CreateDicom(json, OrthancPluginCreateDicomFlags_None);
+  return new OrthancPlugins::FindMatcher(context_, modified);
+#endif
 }
-                          
 
-static void ToLowerCase(std::string& s)
-{
-  std::transform(s.begin(), s.end(), s.begin(), tolower);
-}
 
 
 OrthancPluginErrorCode Callback(OrthancPluginWorklistAnswers*     answers,
@@ -124,59 +131,52 @@ OrthancPluginErrorCode Callback(OrthancPluginWorklistAnswers*     answers,
                                 const char*                       remoteAet,
                                 const char*                       calledAet)
 {
-  namespace fs = boost::filesystem;  
-
-  Json::Value json;
-
-  if (!GetQueryDicom(json, query))
+  try
   {
-    return OrthancPluginErrorCode_InternalError;
-  }
+    // Construct an object to match the worklists in the database against the C-Find query
+    std::auto_ptr<OrthancPlugins::FindMatcher> matcher(CreateMatcher(query, remoteAet));
 
-  {
-    std::string msg = ("Received worklist query from remote modality " + 
-                       std::string(remoteAet) + ":\n" + json.toStyledString());
-    OrthancPluginLogInfo(context_, msg.c_str());
-  }
+    // Loop over the regular files in the database folder
+    namespace fs = boost::filesystem;  
 
-  fs::path source(folder_);
-  fs::directory_iterator end;
+    fs::path source(folder_);
+    fs::directory_iterator end;
 
-  try
-  {
-    for (fs::directory_iterator it(source); it != end; ++it)
+    try
     {
-      fs::file_type type(it->status().type());
-
-      if (type == fs::regular_file ||
-          type == fs::reparse_file)   // cf. BitBucket issue #11
+      for (fs::directory_iterator it(source); it != end; ++it)
       {
-        std::string extension = fs::extension(it->path());
-        ToLowerCase(extension);
+        fs::file_type type(it->status().type());
 
-        if (extension == ".wl")
+        if (type == fs::regular_file ||
+            type == fs::reparse_file)   // cf. BitBucket issue #11
         {
-          OrthancPluginErrorCode error = MatchWorklist(answers, query, it->path().string());
-          if (error)
+          std::string extension = fs::extension(it->path());
+          std::transform(extension.begin(), extension.end(), extension.begin(), tolower);  // Convert to lowercase
+
+          if (extension == ".wl")
           {
-            OrthancPluginLogError(context_, "Error while adding an answer to a worklist request");
-            return error;
+            // We found a worklist (i.e. a DICOM find with extension ".wl"), match it against the query
+            MatchWorklist(answers, query, *matcher, it->path().string());
           }
         }
       }
     }
+    catch (fs::filesystem_error&)
+    {
+      OrthancPlugins::LogError(context_, "Inexistent folder while scanning for worklists: " + source.string());
+      return OrthancPluginErrorCode_DirectoryExpected;
+    }
+
+    // Uncomment the following line if too many answers are to be returned
+    // OrthancPluginMarkWorklistAnswersIncomplete(context_, answers);
+
+    return OrthancPluginErrorCode_Success;
   }
-  catch (fs::filesystem_error&)
+  catch (OrthancPlugins::PluginException& e)
   {
-    std::string description = std::string("Inexistent folder while scanning for worklists: ") + source.string();
-    OrthancPluginLogError(context_, description.c_str());
-    return OrthancPluginErrorCode_DirectoryExpected;
+    return e.GetErrorCode();
   }
-
-  // Uncomment the following line if too many answers are to be returned
-  // OrthancPluginMarkWorklistAnswersIncomplete(context_, answers);
-
-  return OrthancPluginErrorCode_Success;
 }
 
 
@@ -185,8 +185,6 @@ extern "C"
   ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c)
   {
     context_ = c;
-    OrthancPluginLogWarning(context_, "Sample worklist plugin is initializing");
-    OrthancPluginSetDescription(context_, "Serve DICOM modality worklists from a folder with Orthanc.");
 
     /* Check the version of the Orthanc core */
     if (OrthancPluginCheckVersion(c) == 0)
@@ -201,55 +199,31 @@ extern "C"
       return -1;
     }
 
-    Json::Value configuration;
-    if (!ConvertToJson(configuration, OrthancPluginGetConfiguration(context_)))
-    {
-      OrthancPluginLogError(context_, "Cannot access the configuration of the worklist server");
-      return -1;
-    }
+    OrthancPlugins::LogWarning(context_, "Sample worklist plugin is initializing");
+    OrthancPluginSetDescription(context_, "Serve DICOM modality worklists from a folder with Orthanc.");
+
+    OrthancPlugins::OrthancConfiguration configuration(context_);
 
-    bool enabled = false;
+    OrthancPlugins::OrthancConfiguration worklists;
+    configuration.GetSection(worklists, "Worklists");
 
-    if (configuration.isMember("Worklists"))
+    bool enabled = worklists.GetBooleanValue("Enable", false);
+    if (enabled)
     {
-      const Json::Value& config = configuration["Worklists"];
-      if (!config.isMember("Enable") ||
-          config["Enable"].type() != Json::booleanValue)
+      if (worklists.LookupStringValue(folder_, "Database"))
       {
-        OrthancPluginLogError(context_, "The configuration option \"Worklists.Enable\" must contain a Boolean");
-        return -1;
+        OrthancPlugins::LogWarning(context_, "The database of worklists will be read from folder: " + folder_);
+        OrthancPluginRegisterWorklistCallback(context_, Callback);
       }
       else
       {
-        enabled = config["Enable"].asBool();
-        if (enabled)
-        {
-          if (!config.isMember("Database") ||
-              config["Database"].type() != Json::stringValue)
-          {
-            OrthancPluginLogError(context_, "The configuration option \"Worklists.Database\" must contain a path");
-            return -1;
-          }
-
-          folder_ = config["Database"].asString();
-        }
-        else
-        {
-          OrthancPluginLogWarning(context_, "Worklists server is disabled by the configuration file");
-        }
+        OrthancPlugins::LogError(context_, "The configuration option \"Worklists.Database\" must contain a path");
+        return -1;
       }
     }
     else
     {
-      OrthancPluginLogWarning(context_, "Worklists server is disabled, no suitable configuration section was provided");
-    }
-
-    if (enabled)
-    {
-      std::string message = "The database of worklists will be read from folder: " + folder_;
-      OrthancPluginLogWarning(context_, message.c_str());
-
-      OrthancPluginRegisterWorklistCallback(context_, Callback);
+      OrthancPlugins::LogWarning(context_, "Worklists server is disabled by the configuration file");
     }
 
     return 0;
diff --git a/Plugins/Samples/ModalityWorklists/README b/Plugins/Samples/ModalityWorklists/README
index 58ea61b..f54f4e0 100644
--- a/Plugins/Samples/ModalityWorklists/README
+++ b/Plugins/Samples/ModalityWorklists/README
@@ -4,57 +4,8 @@ Introduction
 This sample plugin enables Orthanc to serve DICOM modality worklists
 that are read from some folder.
 
-Whenever a C-Find SCP request is issued to Orthanc, it will read the
-content of this folder to locate the worklists that match the request.
-An external application can dynamically modify the content of this
-folder while Orthanc is running to add/remove worklists.
+The shared library containing the plugin is created as part of the
+build process of Orthanc.
 
-This sample mimics the behavior of the "wlmscpfs" tool from the
-DCMTK package:
-http://support.dcmtk.org/docs/wlmscpfs.html
-
-
-Compilation for Linux
-=====================
-
-# mkdir Build
-# cd Build
-# cmake ..
-# make
-
-
-Cross-compilation for Windows using MinGW
-=========================================
-
-# mkdir Build
-# cd Build
-# cmake .. -DCMAKE_TOOLCHAIN_FILE=../../../Resources/MinGWToolchain.cmake
-# make
-
-
-Configuration
-=============
-
-First, generate the default configuration of Orthanc:
-https://orthanc.chu.ulg.ac.be/book/users/configuration.html
-
-Then, modify the "Plugins" option to point to the folder containing
-the built plugins. Finally, create a section "ModalityWorklists" in
-the configuration file to configure the worklist server. If using the
-build commands above, a sample configuration would read as follows:
-
-{
-  [...]
-  "Plugins" : [ 
-    "."
-  ],
-  "Worklists" : {
-    "Enable": true,
-    "Database": "../WorklistsDatabase"
-  }
-}
-
-The folder "WorklistsDatabase" contains a database of sample
-worklists, that come from the DCMTK source distribution, as described
-in the FAQ entry #37 of the DCMTK project:
-http://forum.dcmtk.org/viewtopic.php?t=84
+Documentation is available in the Orthanc Book:
+http://book.orthanc-server.com/plugins/worklists-plugin.html
diff --git a/Plugins/Samples/ServeFolders/CMakeLists.txt b/Plugins/Samples/ServeFolders/CMakeLists.txt
index e9a3480..e9c611f 100644
--- a/Plugins/Samples/ServeFolders/CMakeLists.txt
+++ b/Plugins/Samples/ServeFolders/CMakeLists.txt
@@ -16,10 +16,13 @@ include(${ORTHANC_ROOT}/Resources/CMake/BoostConfiguration.cmake)
 
 add_library(ServeFolders SHARED 
   Plugin.cpp
+  ${CMAKE_SOURCE_DIR}/../Common/OrthancPluginCppWrapper.cpp
   ${JSONCPP_SOURCES}
   ${BOOST_SOURCES}
   )
 
+add_definitions(-DHAS_ORTHANC_EXCEPTION=0)
+
 message("Setting the version of the plugin to ${SERVE_FOLDERS_VERSION}")
 add_definitions(-DSERVE_FOLDERS_VERSION="${SERVE_FOLDERS_VERSION}")
 
diff --git a/Plugins/Samples/ServeFolders/Plugin.cpp b/Plugins/Samples/ServeFolders/Plugin.cpp
index 6772c83..6e8c64e 100644
--- a/Plugins/Samples/ServeFolders/Plugin.cpp
+++ b/Plugins/Samples/ServeFolders/Plugin.cpp
@@ -18,122 +18,81 @@
  **/
 
 
-#include <orthanc/OrthancCPlugin.h>
+#include "../Common/OrthancPluginCppWrapper.h"
 
 #include <json/reader.h>
 #include <json/value.h>
 #include <boost/filesystem.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+
+#if HAS_ORTHANC_EXCEPTION == 1
+#  error The macro HAS_ORTHANC_EXCEPTION must be set to 0 to compile this plugin
+#endif
+
 
 
 static OrthancPluginContext* context_ = NULL;
+static std::map<std::string, std::string> extensions_;
 static std::map<std::string, std::string> folders_;
 static const char* INDEX_URI = "/app/plugin-serve-folders.html";
+static bool allowCache_ = false;
+static bool generateETag_ = true;
 
 
-static const char* GetMimeType(const std::string& path)
+static void SetHttpHeaders(OrthancPluginRestOutput* output)
 {
-  size_t dot = path.find_last_of('.');
-
-  std::string extension = (dot == std::string::npos) ? "" : path.substr(dot);
-  std::transform(extension.begin(), extension.end(), extension.begin(), tolower);
-
-  if (extension == ".html")
-  {
-    return "text/html";
-  }
-  else if (extension == ".css")
-  {
-    return "text/css";
-  }
-  else if (extension == ".js")
-  {
-    return "application/javascript";
-  }
-  else if (extension == ".gif")
-  {
-    return "image/gif";
-  }
-  else if (extension == ".svg")
-  {
-    return "image/svg+xml";
-  }
-  else if (extension == ".json")
-  {
-    return "application/json";
-  }
-  else if (extension == ".xml")
-  {
-    return "application/xml";
-  }
-  else if (extension == ".png")
-  {
-    return "image/png";
-  }
-  else if (extension == ".jpg" || extension == ".jpeg")
-  {
-    return "image/jpeg";
-  }
-  else if (extension == ".woff")
+  if (!allowCache_)
   {
-    return "application/x-font-woff";
-  }
-  else
-  {
-    std::string s = "Unknown MIME type for extension: " + extension;
-    OrthancPluginLogWarning(context_, s.c_str());
-    return "application/octet-stream";
+    // http://stackoverflow.com/a/2068407/881731
+    OrthancPluginSetHttpHeader(context_, output, "Cache-Control", "no-cache, no-store, must-revalidate");
+    OrthancPluginSetHttpHeader(context_, output, "Pragma", "no-cache");
+    OrthancPluginSetHttpHeader(context_, output, "Expires", "0");
   }
 }
 
 
-static bool ReadFile(std::string& target,
-                     const std::string& path)
+static void RegisterDefaultExtensions()
 {
-  OrthancPluginMemoryBuffer buffer;
-  if (OrthancPluginReadFile(context_, &buffer, path.c_str()))
-  {
-    return false;
-  }
-  else
-  {
-    target.assign(reinterpret_cast<const char*>(buffer.data), buffer.size);
-    OrthancPluginFreeMemoryBuffer(context_, &buffer);
-    return true;
-  }
+  extensions_["css"]  = "text/css";
+  extensions_["gif"]  = "image/gif";
+  extensions_["html"] = "text/html";
+  extensions_["jpeg"] = "image/jpeg";
+  extensions_["jpg"]  = "image/jpeg";
+  extensions_["js"]   = "application/javascript";
+  extensions_["json"] = "application/json";
+  extensions_["nexe"] = "application/x-nacl";
+  extensions_["nmf"]  = "application/json";
+  extensions_["pexe"] = "application/x-pnacl";
+  extensions_["png"]  = "image/png";
+  extensions_["svg"]  = "image/svg+xml";
+  extensions_["woff"] = "application/x-font-woff";
+  extensions_["xml"]  = "application/xml";
 }
 
 
-static bool ReadConfiguration(Json::Value& configuration,
-                              OrthancPluginContext* context)
+static std::string GetMimeType(const std::string& path)
 {
-  std::string s;
+  size_t dot = path.find_last_of('.');
 
-  {
-    char* tmp = OrthancPluginGetConfiguration(context);
-    if (tmp == NULL)
-    {
-      OrthancPluginLogError(context, "Error while retrieving the configuration from Orthanc");
-      return false;
-    }
+  std::string extension = (dot == std::string::npos) ? "" : path.substr(dot + 1);
+  std::transform(extension.begin(), extension.end(), extension.begin(), tolower);
 
-    s.assign(tmp);
-    OrthancPluginFreeString(context, tmp);      
-  }
+  std::map<std::string, std::string>::const_iterator found = extensions_.find(extension);
 
-  Json::Reader reader;
-  if (reader.parse(s, configuration))
+  if (found != extensions_.end() &&
+      !found->second.empty())
   {
-    return true;
+    return found->second;
   }
   else
   {
-    OrthancPluginLogError(context, "Unable to parse the configuration");
-    return false;
+    OrthancPlugins::LogWarning(context_, "ServeFolders: Unknown MIME type for extension \"" + extension + "\"");
+    return "application/octet-stream";
   }
 }
 
 
-
 static bool LookupFolder(std::string& folder,
                          OrthancPluginRestOutput* output,
                          const OrthancPluginHttpRequest* request)
@@ -143,8 +102,7 @@ static bool LookupFolder(std::string& folder,
   std::map<std::string, std::string>::const_iterator found = folders_.find(uri);
   if (found == folders_.end())
   {
-    std::string s = "Unknown URI in plugin server-folders: " + uri;
-    OrthancPluginLogError(context_, s.c_str());
+    OrthancPlugins::LogError(context_, "Unknown URI in plugin server-folders: " + uri);
     OrthancPluginSendHttpStatusCode(context_, output, 404);
     return false;
   }
@@ -156,16 +114,35 @@ static bool LookupFolder(std::string& folder,
 }
 
 
-static OrthancPluginErrorCode FolderCallback(OrthancPluginRestOutput* output,
-                                             const char* url,
-                                             const OrthancPluginHttpRequest* request)
+static void Answer(OrthancPluginRestOutput* output,
+                   const char* content,
+                   size_t size,
+                   const std::string& mime)
+{
+  if (generateETag_)
+  {
+    OrthancPlugins::OrthancString md5(context_);
+    md5.Assign(OrthancPluginComputeMd5(context_, content, size));
+
+    std::string etag = "\"" + std::string(md5.GetContent()) + "\"";
+    OrthancPluginSetHttpHeader(context_, output, "ETag", etag.c_str());
+  }
+
+  SetHttpHeaders(output);
+  OrthancPluginAnswerBuffer(context_, output, content, size, mime.c_str());
+}
+
+
+void ServeFolder(OrthancPluginRestOutput* output,
+                 const char* url,
+                 const OrthancPluginHttpRequest* request)
 {
   namespace fs = boost::filesystem;  
 
   if (request->method != OrthancPluginHttpMethod_Get)
   {
     OrthancPluginSendMethodNotAllowed(context_, output, "GET");
-    return OrthancPluginErrorCode_Success;
+    return;
   }
 
   std::string folder;
@@ -212,40 +189,42 @@ static OrthancPluginErrorCode FolderCallback(OrthancPluginRestOutput* output,
       s += "  </body>\n";
       s += "</html>\n";
 
-      OrthancPluginAnswerBuffer(context_, output, s.c_str(), s.size(), "text/html");
+      Answer(output, s.c_str(), s.size(), "text/html");
     }
     else
     {
       std::string path = folder + "/" + item.string();
-      const char* mime = GetMimeType(path);
+      std::string mime = GetMimeType(path);
 
-      std::string s;
-      if (ReadFile(s, path))
+      OrthancPlugins::MemoryBuffer content(context_);
+
+      try
       {
-        const char* resource = s.size() ? s.c_str() : NULL;
-        OrthancPluginAnswerBuffer(context_, output, resource, s.size(), mime);
+        content.ReadFile(path);
       }
-      else
+      catch (...)
       {
-        std::string s = "Inexistent file in served folder: " + path;
-        OrthancPluginLogError(context_, s.c_str());
-        OrthancPluginSendHttpStatusCode(context_, output, 404);
+        ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InexistentFile);
       }
+
+      boost::posix_time::ptime lastModification = boost::posix_time::from_time_t(fs::last_write_time(path));
+      std::string t = boost::posix_time::to_iso_string(lastModification);
+      OrthancPluginSetHttpHeader(context_, output, "Last-Modified", t.c_str());
+
+      Answer(output, content.GetData(), content.GetSize(), mime);
     }
   }
-
-  return OrthancPluginErrorCode_Success;
 }
 
 
-static OrthancPluginErrorCode ListServedFolders(OrthancPluginRestOutput* output,
-                                                const char* url,
-                                                const OrthancPluginHttpRequest* request)
+void ListServedFolders(OrthancPluginRestOutput* output,
+                       const char* url,
+                       const OrthancPluginHttpRequest* request)
 {
   if (request->method != OrthancPluginHttpMethod_Get)
   {
     OrthancPluginSendMethodNotAllowed(context_, output, "GET");
-    return OrthancPluginErrorCode_Success;
+    return;
   }
 
   std::string s = "<html><body><h1>Additional folders served by Orthanc</h1>\n";
@@ -269,102 +248,197 @@ static OrthancPluginErrorCode ListServedFolders(OrthancPluginRestOutput* output,
 
   s += "</body></html>\n";
 
-  OrthancPluginAnswerBuffer(context_, output, s.c_str(), s.size(), "text/html");
+  Answer(output, s.c_str(), s.size(), "text/html");
+}
+
+
+static void ConfigureFolders(const Json::Value& folders)
+{
+  if (folders.type() != Json::objectValue)
+  {
+    OrthancPlugins::LogError(context_, "The list of folders to be served is badly formatted (must be a JSON object)");
+    ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+  }
+
+  Json::Value::Members members = folders.getMemberNames();
+
+  // Register the callback for each base URI
+  for (Json::Value::Members::const_iterator 
+         it = members.begin(); it != members.end(); ++it)
+  {
+    if (folders[*it].type() != Json::stringValue)
+    {
+      OrthancPlugins::LogError(context_, "The folder to be served \"" + *it + 
+                               "\" must be associated with a string value (its mapped URI)");
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+
+    std::string baseUri = *it;
+
+    // Remove the heading and trailing slashes in the root URI, if any
+    while (!baseUri.empty() &&
+           *baseUri.begin() == '/')
+    {
+      baseUri = baseUri.substr(1);
+    }
+
+    while (!baseUri.empty() &&
+           *baseUri.rbegin() == '/')
+    {
+      baseUri.resize(baseUri.size() - 1);
+    }
+
+    if (baseUri.empty())
+    {
+      OrthancPlugins::LogError(context_, "The URI of a folder to be served cannot be empty");
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+    }
+
+    // Check whether the source folder exists and is indeed a directory
+    const std::string folder = folders[*it].asString();
+    if (!boost::filesystem::is_directory(folder))
+    {
+      OrthancPlugins::LogError(context_, "Trying and serve an inexistent folder: " + folder);
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InexistentFile);
+    }
 
-  return OrthancPluginErrorCode_Success;
+    folders_[baseUri] = folder;
+
+    // Register the callback to serve the folder
+    {
+      const std::string regex = "/(" + baseUri + ")/(.*)";
+      OrthancPlugins::RegisterRestCallback<ServeFolder>(context_, regex.c_str(), true);
+    }
+  }
 }
 
 
-extern "C"
+static void ConfigureExtensions(const Json::Value& extensions)
 {
-  ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
+  if (extensions.type() != Json::objectValue)
   {
-    context_ = context;
+    OrthancPlugins::LogError(context_, "The list of extensions is badly formatted (must be a JSON object)");
+    ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+  }
 
-    /* Check the version of the Orthanc core */
-    if (OrthancPluginCheckVersion(context_) == 0)
+  Json::Value::Members members = extensions.getMemberNames();
+
+  for (Json::Value::Members::const_iterator 
+         it = members.begin(); it != members.end(); ++it)
+  {
+    if (extensions[*it].type() != Json::stringValue)
     {
-      char info[1024];
-      sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin",
-              context_->orthancVersion,
-              ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER,
-              ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER,
-              ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER);
-      OrthancPluginLogError(context_, info);
-      return -1;
+      OrthancPlugins::LogError(context_, "The file extension \"" + *it + 
+                               "\" must be associated with a string value (its MIME type)");
+      ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
     }
 
-    OrthancPluginSetDescription(context_, "Serve additional folders with the HTTP server of Orthanc.");
+    const std::string& mime = extensions[*it].asString();
+
+    std::string name = *it;
 
-    Json::Value configuration;
-    if (!ReadConfiguration(configuration, context_))
+    if (!name.empty() &&
+        name[0] == '.')
     {
-      return -1;
+      name = name.substr(1);  // Remove the leading dot "."
     }
 
-    if (configuration.isMember("ServeFolders"))
+    extensions_[name] = mime;
+
+    if (mime.empty())
     {
-      if (configuration["ServeFolders"].type() != Json::objectValue)
-      {
-        OrthancPluginLogError(context_, "The \"ServeFolders\" configuration section is badly formatted (must be a JSON object)");
-        return -1;
-      }
+      OrthancPlugins::LogWarning(context_, "ServeFolders: Removing MIME type for file extension \"." + name + "\"");
     }
     else
     {
-      OrthancPluginLogWarning(context_, "No section \"ServeFolders\" in your configuration file: "
-                              "No additional folder will be served!");
-      configuration["ServeFolders"] = Json::objectValue;
+      OrthancPlugins::LogWarning(context_, "ServeFolders: Associating file extension \"." + name + 
+                                 "\" with MIME type \"" + mime + "\"");
     }
+  }  
+}
 
 
-    Json::Value::Members members = configuration["ServeFolders"].getMemberNames();
+static void ReadConfiguration()
+{
+  OrthancPlugins::OrthancConfiguration configuration;
+
+  {
+    OrthancPlugins::OrthancConfiguration globalConfiguration(context_);
+    globalConfiguration.GetSection(configuration, "ServeFolders");
+  }
+
+  if (!configuration.IsSection("Folders"))
+  {
+    // This is a basic configuration
+    ConfigureFolders(configuration.GetJson());
+  }
+  else
+  {
+    // This is an advanced configuration
+    ConfigureFolders(configuration.GetJson()["Folders"]);
+
+    bool tmp;
 
-    // Register the callback for each base URI
-    for (Json::Value::Members::const_iterator 
-           it = members.begin(); it != members.end(); ++it)
+    if (configuration.LookupBooleanValue(tmp, "AllowCache"))
     {
-      std::string baseUri = *it;
+      allowCache_ = tmp;
+      OrthancPlugins::LogWarning(context_, "ServeFolders: Requesting the HTTP client to " +
+                                 std::string(tmp ? "enable" : "disable") + 
+                                 " its caching mechanism");
+    }
 
-      // Remove the heading and trailing slashes in the root URI, if any
-      while (!baseUri.empty() &&
-             *baseUri.begin() == '/')
-      {
-        baseUri = baseUri.substr(1);
-      }
+    if (configuration.LookupBooleanValue(tmp, "GenerateETag"))
+    {
+      generateETag_ = tmp;
+      OrthancPlugins::LogWarning(context_, "ServeFolders: The computation of an ETag for the served resources is " +
+                                 std::string(tmp ? "enabled" : "disabled"));
+    }
 
-      while (!baseUri.empty() &&
-             *baseUri.rbegin() == '/')
-      {
-        baseUri.resize(baseUri.size() - 1);
-      }
+    OrthancPlugins::OrthancConfiguration extensions;
+    configuration.GetSection(extensions, "Extensions");
+    ConfigureExtensions(extensions.GetJson());
+  }
 
-      if (baseUri.empty())
-      {
-        OrthancPluginLogError(context_, "The URI of a folder to be served cannot be empty");
-        return -1;
-      }
+  if (folders_.empty())
+  {
+    OrthancPlugins::LogWarning(context_, "ServeFolders: Empty configuration file: No additional folder will be served!");
+  }
+}
 
-      // Check whether the source folder exists and is indeed a directory
-      const std::string folder = configuration["ServeFolders"][*it].asString();
-      if (!boost::filesystem::is_directory(folder))
-      {
-        std::string msg = "Trying and serve an inexistent folder: " + folder;
-        OrthancPluginLogError(context_, msg.c_str());
-        return -1;
-      }
 
-      folders_[baseUri] = folder;
+extern "C"
+{
+  ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
+  {
+    context_ = context;
 
-      // Register the callback to serve the folder
-      {
-        const std::string regex = "/(" + baseUri + ")/(.*)";
-        OrthancPluginRegisterRestCallback(context, regex.c_str(), FolderCallback);
-      }
+    /* Check the version of the Orthanc core */
+    if (OrthancPluginCheckVersion(context_) == 0)
+    {
+      char info[1024];
+      sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin",
+              context_->orthancVersion,
+              ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER,
+              ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER,
+              ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER);
+      OrthancPluginLogError(context_, info);
+      return -1;
     }
 
-    OrthancPluginRegisterRestCallback(context, INDEX_URI, ListServedFolders);
+    RegisterDefaultExtensions();
+    OrthancPluginSetDescription(context_, "Serve additional folders with the HTTP server of Orthanc.");
     OrthancPluginSetRootUri(context, INDEX_URI);
+    OrthancPlugins::RegisterRestCallback<ListServedFolders>(context_, INDEX_URI, true);
+
+    try
+    {
+      ReadConfiguration();
+    }
+    catch (OrthancPlugins::PluginException& e)
+    {
+      OrthancPlugins::LogError(context_, "Error while initializing the ServeFolders plugin: " + 
+                               std::string(e.What(context_)));
+    }
 
     return 0;
   }
diff --git a/Plugins/Samples/ServeFolders/README b/Plugins/Samples/ServeFolders/README
index 3ba1f84..ed50f3f 100644
--- a/Plugins/Samples/ServeFolders/README
+++ b/Plugins/Samples/ServeFolders/README
@@ -1,52 +1,11 @@
-Introduction
-============
+ServeFolders plugin
+===================
 
 This sample plugin enables Orthanc to serve additional folders using
 its embedded Web server.
 
+The shared library containing the plugin is created as part of the
+build process of Orthanc.
 
-Compilation for Linux
-=====================
-
-# mkdir Build
-# cd Build
-# cmake ..
-# make
-
-
-Cross-compilation for Windows using MinGW
-=========================================
-
-# mkdir Build
-# cd Build
-# cmake .. -DCMAKE_TOOLCHAIN_FILE=../../../Resources/MinGWToolchain.cmake
-# make
-
-
-Configuration
-=============
-
-First, generate the default configuration of Orthanc:
-https://orthanc.chu.ulg.ac.be/book/users/configuration.html
-
-Then, modify the "Plugins" option to point to the folder containing
-the built plugins.
-
-Finally, create a section "ServeFolders" in the configuration file to
-specify which folder you want to serve, and at which URI. For
-instance, the following excerpt would load the plugins from the
-working directory, then would branch the content of the folder
-"/home/jodogne/WWW/fosdem" as the URI "http://localhost:8042/fosdem":
-
-{
-  "Name" : "MyOrthanc",
-  [...]
-  "HttpPort" : 8042,
-  [...]
-  "Plugins" : [ 
-    "."
-  ],
-  "ServeFolders" : {
-    "/fosdem" : "/home/jodogne/WWW/fosdem"
-  }
-}
+Documentation is available in the Orthanc Book:
+http://book.orthanc-server.com/plugins/serve-folders.html
diff --git a/README b/README
index 35859b2..38cc685 100644
--- a/README
+++ b/README
@@ -16,11 +16,11 @@ file.
 Supported Platforms
 -------------------
 
-Currently, the supported platforms are:
+Currently, the officially supported platforms are:
 
-* Linux 32bit.
-* Linux 64bit.
+* GNU/Linux (32bit and 64bit).
 * Windows 32bit.
+* Apple OS X (32bit and 64bit).
 
 
 Supported Toolchains
@@ -29,9 +29,9 @@ Supported Toolchains
 Orthanc can currently be built using the following compiling
 toolchains:
 
-* Native Linux compilation, with gcc.
+* Native GNU/Linux compilation, with gcc.
 * Native Windows compilation, with Microsoft Visual Studio.
-* Cross-compilation for Windows under Linux, with MinGW.
+* Cross-compilation for Windows under GNU/Linux, with MinGW.
 
 
 Licensing
diff --git a/Resources/CMake/BoostConfiguration.cmake b/Resources/CMake/BoostConfiguration.cmake
index 20c50df..fa54bf5 100644
--- a/Resources/CMake/BoostConfiguration.cmake
+++ b/Resources/CMake/BoostConfiguration.cmake
@@ -43,7 +43,7 @@ if (BOOST_STATIC)
   set(BOOST_NAME boost_1_60_0)
   set(BOOST_BCP_SUFFIX bcpdigest-1.0.1)
   set(BOOST_MD5 "a789f8ec2056ad1c2d5f0cb64687cc7b")
-  set(BOOST_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz")
+  set(BOOST_URL "http://www.orthanc-server.com/downloads/third-party/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz")
   set(BOOST_FILESYSTEM_SOURCES_DIR "${BOOST_NAME}/libs/filesystem/src") 
   set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME})
 
@@ -54,8 +54,12 @@ if (BOOST_STATIC)
   if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
       ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR
       ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
-      ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD")
+      ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
+      ${CMAKE_SYSTEM_NAME} STREQUAL "PNaCl" OR
+      ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl32" OR
+      ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl64")
     list(APPEND BOOST_SOURCES
+      ${BOOST_SOURCES_DIR}/libs/atomic/src/lockpool.cpp
       ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/once.cpp
       ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/thread.cpp
       )
@@ -65,7 +69,10 @@ if (BOOST_STATIC)
       -DBOOST_LOCALE_NO_STD_BACKEND=1
       )
 
-    if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
+    if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase" OR
+        ${CMAKE_SYSTEM_NAME} STREQUAL "PNaCl" OR
+        ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl32" OR
+        ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl64")
       add_definitions(-DBOOST_HAS_SCHED_YIELD=1)
     endif()
 
@@ -107,19 +114,38 @@ if (BOOST_STATIC)
   list(APPEND BOOST_SOURCES
     ${BOOST_REGEX_SOURCES}
     ${BOOST_SOURCES_DIR}/libs/date_time/src/gregorian/greg_month.cpp
-    ${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp
-    ${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp
-    ${BOOST_FILESYSTEM_SOURCES_DIR}/path.cpp
-    ${BOOST_FILESYSTEM_SOURCES_DIR}/path_traits.cpp
     ${BOOST_SOURCES_DIR}/libs/locale/src/encoding/codepage.cpp
     ${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp
     )
 
+  if (${CMAKE_SYSTEM_NAME} STREQUAL "PNaCl" OR
+      ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl32" OR
+      ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl64")
+    # boost::filesystem is not available on PNaCl
+    add_definitions(
+      -DBOOST_HAS_FILESYSTEM_V3=0
+      -D__INTEGRITY=1
+      )
+  else()
+    add_definitions(
+      -DBOOST_HAS_FILESYSTEM_V3=1
+      )
+    list(APPEND BOOST_SOURCES
+      ${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp
+      ${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp
+      ${BOOST_FILESYSTEM_SOURCES_DIR}/path.cpp
+      ${BOOST_FILESYSTEM_SOURCES_DIR}/path_traits.cpp
+      )
+  endif()
+
   if (USE_BOOST_LOCALE_BACKENDS)
     if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
         ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR
         ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
-        ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD")
+        ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
+        ${CMAKE_SYSTEM_NAME} STREQUAL "PNaCl" OR
+        ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl32" OR
+        ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl64")
       list(APPEND BOOST_SOURCES
         ${BOOST_SOURCES_DIR}/libs/locale/src/posix/codecvt.cpp
         ${BOOST_SOURCES_DIR}/libs/locale/src/posix/collate.cpp
@@ -175,7 +201,6 @@ if (BOOST_STATIC)
     -DBOOST_SYSTEM_NO_LIB
     -DBOOST_LOCALE_NO_LIB
     -DBOOST_HAS_LOCALE=1
-    -DBOOST_HAS_FILESYSTEM_V3=1
     )
 
   if (CMAKE_COMPILER_IS_GNUCXX)
@@ -186,7 +211,8 @@ if (BOOST_STATIC)
     ${BOOST_SOURCES_DIR}
     )
 
-  source_group(ThirdParty\\Boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*)
+  source_group(ThirdParty\\boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*)
+
 else()
   add_definitions(
     -DBOOST_HAS_LOCALE=1
diff --git a/Resources/CMake/Compiler.cmake b/Resources/CMake/Compiler.cmake
index 52f4fab..fa7577d 100644
--- a/Resources/CMake/Compiler.cmake
+++ b/Resources/CMake/Compiler.cmake
@@ -41,7 +41,17 @@ elseif (MSVC)
     -D_CRT_SECURE_NO_WARNINGS=1
     -D_CRT_SECURE_NO_DEPRECATE=1
     )
-  include_directories(${ORTHANC_ROOT}/Resources/ThirdParty/VisualStudio)
+
+  if (MSVC_VERSION LESS 1600)
+    # Starting with Visual Studio >= 2010 (i.e. macro _MSC_VER >=
+    # 1600), Microsoft ships a standard-compliant <stdint.h>
+    # header. For earlier versions of Visual Studio, give access to a
+    # compatibility header.
+    # http://stackoverflow.com/a/70630/881731
+    # https://en.wikibooks.org/wiki/C_Programming/C_Reference/stdint.h#External_links
+    include_directories(${ORTHANC_ROOT}/Resources/ThirdParty/VisualStudio)
+  endif()
+
   link_libraries(netapi32)
 endif()
 
@@ -154,6 +164,23 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
 endif()
 
 
+if (DEFINED ENABLE_PROFILING AND ENABLE_PROFILING)
+  if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+    message(WARNING "Enabling profiling on a non-debug build will not produce full information")
+  endif()
+
+  if (CMAKE_COMPILER_IS_GNUCXX)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg")
+    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg")
+    set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -pg")
+    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg")
+  else()
+    message(FATAL_ERROR "Don't know how to enable profiling on your configuration")
+  endif()
+endif()
+
+
 if (STATIC_BUILD)
   add_definitions(-DORTHANC_STATIC=1)
 else()
diff --git a/Resources/CMake/DcmtkConfiguration.cmake b/Resources/CMake/DcmtkConfiguration.cmake
index 0e22007..8534a93 100644
--- a/Resources/CMake/DcmtkConfiguration.cmake
+++ b/Resources/CMake/DcmtkConfiguration.cmake
@@ -7,7 +7,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
     SET(DCMTK_VERSION_NUMBER 361)
     SET(DCMTK_PACKAGE_VERSION "3.6.1")
     SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.1_20160216)
-    SET(DCMTK_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/dcmtk-3.6.1_20160216.tar.gz")
+    SET(DCMTK_URL "http://www.orthanc-server.com/downloads/third-party/dcmtk-3.6.1_20160216.tar.gz")
     SET(DCMTK_MD5 "273c8a544b9fe09b8a4fb4eb51df8e52")
     SET(DCMTK_PATCH_SPEED "${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.1-speed.patch")
 
@@ -21,7 +21,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
     SET(DCMTK_VERSION_NUMBER 360)
     SET(DCMTK_PACKAGE_VERSION "3.6.0")
     SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.0)
-    SET(DCMTK_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/dcmtk-3.6.0.zip")
+    SET(DCMTK_URL "http://www.orthanc-server.com/downloads/third-party/dcmtk-3.6.0.zip")
     SET(DCMTK_MD5 "219ad631b82031806147e4abbfba4fa4")
     SET(DCMTK_PATCH_SPEED "${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-speed.patch")
     SET(DCMTK_PATCH_MINGW64 "${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-mingw64.patch")
@@ -35,6 +35,35 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
 
   DownloadPackage(${DCMTK_MD5} ${DCMTK_URL} "${DCMTK_SOURCES_DIR}")
 
+  
+  if (FirstRun AND
+      NOT USE_DCMTK_361)
+    if (USE_DCMTK_361_PRIVATE_DIC)
+      # If using DCMTK 3.6.0, backport the "private.dic" file from DCMTK
+      # 3.6.1 snapshot. This adds support for more private tags, and
+      # fixes some import problems with Philips MRI Achieva.
+      message("Using the dictionary of private tags from DCMTK 3.6.1")
+      configure_file(
+        ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.1-private.dic
+        ${DCMTK_SOURCES_DIR}/dcmdata/data/private.dic
+        COPYONLY)
+    else()
+      message("Using the dictionary of private tags from DCMTK 3.6.0")
+    endif()
+
+    # Patches specific to DCMTK 3.6.0
+    execute_process(
+      COMMAND ${PATCH_EXECUTABLE} -p0 -N -i ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch
+      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+      RESULT_VARIABLE Failure
+      )
+
+    if (Failure)
+      message(FATAL_ERROR "Error while patching a file")
+    endif()
+  endif()
+
+
   IF (CMAKE_CROSSCOMPILING)
     SET(C_CHAR_UNSIGNED 1 CACHE INTERNAL "Whether char is unsigned.")
   ENDIF()
@@ -181,9 +210,15 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
   list(REMOVE_ITEM DCMTK_SOURCES 
     ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdictbi.cc
     ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdeftag.cc
-    #${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdictbi.cc
     )
 
+  if (NOT USE_DCMTK_361)
+    # Removing this file is required with DCMTK 3.6.0
+    list(REMOVE_ITEM DCMTK_SOURCES 
+      ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdictbi.cc
+      )
+  endif()
+
   #set_source_files_properties(${DCMTK_SOURCES}
   #  PROPERTIES COMPILE_DEFINITIONS
   #  "PACKAGE_VERSION=\"${DCMTK_PACKAGE_VERSION}\";PACKAGE_VERSION_NUMBER=\"${DCMTK_VERSION_NUMBER}\"")
@@ -271,6 +306,9 @@ if (NOT DCMTK_USE_EMBEDDED_DICTIONARIES)
       /usr/share/libdcmtk4
       /usr/share/libdcmtk5
       /usr/share/libdcmtk6
+      /usr/share/libdcmtk7
+      /usr/share/libdcmtk8
+      /usr/share/libdcmtk9
       /usr/local/share/dcmtk
       )
 
diff --git a/Resources/CMake/DownloadPackage.cmake b/Resources/CMake/DownloadPackage.cmake
index 492a352..2a73cda 100644
--- a/Resources/CMake/DownloadPackage.cmake
+++ b/Resources/CMake/DownloadPackage.cmake
@@ -15,12 +15,18 @@ endmacro()
 ## Setup the patch command-line tool
 ##
 
-if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
-  set(PATCH_EXECUTABLE ${CMAKE_SOURCE_DIR}/Resources/ThirdParty/patch/patch.exe)
-else ()
-  find_program(PATCH_EXECUTABLE patch)
-  if (${PATCH_EXECUTABLE} MATCHES "PATCH_EXECUTABLE-NOTFOUND")
-    message(FATAL_ERROR "Please install the 'patch' standard command-line tool")
+if (NOT ORTHANC_DISABLE_PATCH)
+  if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
+    set(PATCH_EXECUTABLE ${CMAKE_CURRENT_LIST_DIR}/../ThirdParty/patch/patch.exe)
+    if (NOT EXISTS ${PATCH_EXECUTABLE})
+      message(FATAL_ERROR "Unable to find the patch.exe tool that is shipped with Orthanc")
+    endif()
+
+  else ()
+    find_program(PATCH_EXECUTABLE patch)
+    if (${PATCH_EXECUTABLE} MATCHES "PATCH_EXECUTABLE-NOTFOUND")
+      message(FATAL_ERROR "Please install the 'patch' standard command-line tool")
+    endif()
   endif()
 endif()
 
@@ -70,7 +76,9 @@ macro(DownloadPackage MD5 Url TargetDirectory)
 	message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON")
       endif()
 
-      file(DOWNLOAD "${Url}" "${TMP_PATH}" SHOW_PROGRESS EXPECTED_MD5 "${MD5}")
+      file(DOWNLOAD "${Url}" "${TMP_PATH}" 
+        SHOW_PROGRESS EXPECTED_MD5 "${MD5}"
+        TIMEOUT 60 INACTIVITY_TIMEOUT 60)
     else()
       message("Using local copy of ${Url}")
     endif()
diff --git a/Resources/CMake/GoogleTestConfiguration.cmake b/Resources/CMake/GoogleTestConfiguration.cmake
index af6e67b..b9074b4 100644
--- a/Resources/CMake/GoogleTestConfiguration.cmake
+++ b/Resources/CMake/GoogleTestConfiguration.cmake
@@ -1,15 +1,32 @@
 if (USE_GTEST_DEBIAN_SOURCE_PACKAGE)
-  set(GTEST_SOURCES /usr/src/gtest/src/gtest-all.cc)
-  include_directories(/usr/src/gtest)
+  find_path(GTEST_DEBIAN_SOURCES_DIR
+    NAMES src/gtest-all.cc
+    PATHS
+    /usr/src/gtest
+    /usr/src/googletest/googletest
+    PATH_SUFFIXES src
+    )
+
+  find_path(GTEST_DEBIAN_INCLUDE_DIR
+    NAMES gtest.h
+    PATHS
+    /usr/include/gtest
+    )
 
-  if (NOT EXISTS /usr/include/gtest/gtest.h OR
-      NOT EXISTS ${GTEST_SOURCES})
+  message("Path to the Debian Google Test sources: ${GTEST_DEBIAN_SOURCES_DIR}")
+  message("Path to the Debian Google Test includes: ${GTEST_DEBIAN_INCLUDE_DIR}")
+
+  set(GTEST_SOURCES ${GTEST_DEBIAN_SOURCES_DIR}/src/gtest-all.cc)
+  include_directories(${GTEST_DEBIAN_SOURCES_DIR})
+
+  if (NOT EXISTS ${GTEST_SOURCES} OR
+      NOT EXISTS ${GTEST_DEBIAN_INCLUDE_DIR}/gtest.h)
     message(FATAL_ERROR "Please install the libgtest-dev package")
   endif()
 
 elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST)
   set(GTEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/gtest-1.7.0)
-  set(GTEST_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/gtest-1.7.0.zip")
+  set(GTEST_URL "http://www.orthanc-server.com/downloads/third-party/gtest-1.7.0.zip")
   set(GTEST_MD5 "2d6ec8ccdf5c46b05ba54a9fd1d130d7")
 
   DownloadPackage(${GTEST_MD5} ${GTEST_URL} "${GTEST_SOURCES_DIR}")
@@ -28,6 +45,8 @@ elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST)
     add_definitions(/D _VARIADIC_MAX=10)
   endif()
 
+  source_group(ThirdParty\\GoogleTest REGULAR_EXPRESSION ${GTEST_SOURCES_DIR}/.*)
+
 else()
   include(FindGTest)
   if (NOT GTEST_FOUND)
diff --git a/Resources/CMake/JsonCppConfiguration.cmake b/Resources/CMake/JsonCppConfiguration.cmake
index bad61b8..1532a81 100644
--- a/Resources/CMake/JsonCppConfiguration.cmake
+++ b/Resources/CMake/JsonCppConfiguration.cmake
@@ -1,6 +1,6 @@
 if (STATIC_BUILD OR NOT USE_SYSTEM_JSONCPP)
   set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-0.10.5)
-  set(JSONCPP_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/jsoncpp-0.10.5.tar.gz")
+  set(JSONCPP_URL "http://www.orthanc-server.com/downloads/third-party/jsoncpp-0.10.5.tar.gz")
   set(JSONCPP_MD5 "db146bac5a126ded9bd728ab7b61ed6b")
 
   DownloadPackage(${JSONCPP_MD5} ${JSONCPP_URL} "${JSONCPP_SOURCES_DIR}")
diff --git a/Resources/CMake/LibCurlConfiguration.cmake b/Resources/CMake/LibCurlConfiguration.cmake
index d10912a..390a1a7 100644
--- a/Resources/CMake/LibCurlConfiguration.cmake
+++ b/Resources/CMake/LibCurlConfiguration.cmake
@@ -1,7 +1,7 @@
 if (STATIC_BUILD OR NOT USE_SYSTEM_CURL)
-  SET(CURL_SOURCES_DIR ${CMAKE_BINARY_DIR}/curl-7.44.0)
-  SET(CURL_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/curl-7.44.0.tar.gz")
-  SET(CURL_MD5 "cf46112b5151e2f1a3fd38439bdade23")
+  SET(CURL_SOURCES_DIR ${CMAKE_BINARY_DIR}/curl-7.50.3)
+  SET(CURL_URL "http://www.orthanc-server.com/downloads/third-party/curl-7.50.3.tar.gz")
+  SET(CURL_MD5 "870e16fd88a88b52e26a4f04dfc161db")
 
   DownloadPackage(${CURL_MD5} ${CURL_URL} "${CURL_SOURCES_DIR}")
 
@@ -10,6 +10,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_CURL)
     )
 
   AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib CURL_SOURCES)
+  AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib/vauth CURL_SOURCES)
   AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib/vtls CURL_SOURCES)
   source_group(ThirdParty\\LibCurl REGULAR_EXPRESSION ${CURL_SOURCES_DIR}/.*)
 
@@ -40,13 +41,21 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_CURL)
       )
   endif()
 
-  file(WRITE ${CURL_SOURCES_DIR}/lib/curl_config.h "")
+  if (NOT EXISTS "${CURL_SOURCES_DIR}/lib/curl_config.h")
+    file(WRITE ${CURL_SOURCES_DIR}/lib/curl_config.h "")
 
-  file(GLOB CURL_LIBS_HEADERS ${CURL_SOURCES_DIR}/lib/*.h)
-  foreach (header IN LISTS CURL_LIBS_HEADERS)
-    get_filename_component(filename ${header} NAME)
-    file(WRITE ${CURL_SOURCES_DIR}/lib/vtls/${filename} "#include \"../${filename}\"\n")
-  endforeach()
+    file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/vauth.h "#include \"../vauth.h\"\n")
+    file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/digest.h "#include \"../digest.h\"\n")
+    file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/ntlm.h "#include \"../ntlm.h\"\n")
+    file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vtls/vtls.h "#include \"../../vtls/vtls.h\"\n")
+
+    file(GLOB CURL_LIBS_HEADERS ${CURL_SOURCES_DIR}/lib/*.h)
+    foreach (header IN LISTS CURL_LIBS_HEADERS)
+      get_filename_component(filename ${header} NAME)
+      file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/${filename} "#include \"../${filename}\"\n")
+      file(WRITE ${CURL_SOURCES_DIR}/lib/vtls/${filename} "#include \"../${filename}\"\n")
+    endforeach()
+  endif()
 
   if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
       ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR
diff --git a/Resources/CMake/LibIconvConfiguration.cmake b/Resources/CMake/LibIconvConfiguration.cmake
index be7cd75..d381798 100644
--- a/Resources/CMake/LibIconvConfiguration.cmake
+++ b/Resources/CMake/LibIconvConfiguration.cmake
@@ -1,5 +1,5 @@
 set(LIBICONV_SOURCES_DIR ${CMAKE_BINARY_DIR}/libiconv-1.14)
-set(LIBICONV_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/libiconv-1.14.tar.gz")
+set(LIBICONV_URL "http://www.orthanc-server.com/downloads/third-party/libiconv-1.14.tar.gz")
 set(LIBICONV_MD5 "e34509b1623cec449dfeb73d7ce9c6c6")
 
 DownloadPackage(${LIBICONV_MD5} ${LIBICONV_URL} "${LIBICONV_SOURCES_DIR}")
@@ -48,3 +48,5 @@ list(APPEND BOOST_SOURCES
   ${LIBICONV_SOURCES_DIR}/libcharset/lib/localcharset.c  
   ${LIBICONV_SOURCES_DIR}/libcharset/lib/relocatable.c
   )
+
+source_group(ThirdParty\\libiconv REGULAR_EXPRESSION ${LIBICONV_SOURCES_DIR}/.*)
diff --git a/Resources/CMake/LibJpegConfiguration.cmake b/Resources/CMake/LibJpegConfiguration.cmake
index d0ecdd1..dcc4149 100644
--- a/Resources/CMake/LibJpegConfiguration.cmake
+++ b/Resources/CMake/LibJpegConfiguration.cmake
@@ -2,7 +2,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBJPEG)
   set(LIBJPEG_SOURCES_DIR ${CMAKE_BINARY_DIR}/jpeg-9a)
   DownloadPackage(
     "3353992aecaee1805ef4109aadd433e7"
-    "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/jpegsrc.v9a.tar.gz"
+    "http://www.orthanc-server.com/downloads/third-party/jpegsrc.v9a.tar.gz"
     "${LIBJPEG_SOURCES_DIR}")
 
   include_directories(
@@ -81,6 +81,8 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBJPEG)
     ${LIBJPEG_SOURCES_DIR}/jconfig.h COPYONLY
     )
 
+  source_group(ThirdParty\\libjpeg REGULAR_EXPRESSION ${LIBJPEG_SOURCES_DIR}/.*)
+
 else()
   include(FindJPEG)
 
diff --git a/Resources/CMake/LibP11Configuration.cmake b/Resources/CMake/LibP11Configuration.cmake
index 509bee6..21ab70d 100644
--- a/Resources/CMake/LibP11Configuration.cmake
+++ b/Resources/CMake/LibP11Configuration.cmake
@@ -1,6 +1,6 @@
 if (STATIC_BUILD OR NOT USE_SYSTEM_LIBP11)
   SET(LIBP11_SOURCES_DIR ${CMAKE_BINARY_DIR}/libp11-0.4.0)
-  SET(LIBP11_URL "www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/beid/libp11-0.4.0.tar.gz")
+  SET(LIBP11_URL "http://www.orthanc-server.com/downloads/third-party/beid/libp11-0.4.0.tar.gz")
   SET(LIBP11_MD5 "00b3e41db5be840d822bda12f3ab2ca7")
  
   if (IS_DIRECTORY "${LIBP11_SOURCES_DIR}")
@@ -54,6 +54,8 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBP11)
       )
   endif()
 
+  source_group(ThirdParty\\libp11 REGULAR_EXPRESSION ${LIBP11_SOURCES_DIR}/.*)
+
 else()
   check_include_file_cxx(libp11.h HAVE_LIBP11_H)
   if (NOT HAVE_LIBP11_H)
diff --git a/Resources/CMake/LibPngConfiguration.cmake b/Resources/CMake/LibPngConfiguration.cmake
index 903079f..bf9820c 100644
--- a/Resources/CMake/LibPngConfiguration.cmake
+++ b/Resources/CMake/LibPngConfiguration.cmake
@@ -1,6 +1,6 @@
 if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPNG)
   SET(LIBPNG_SOURCES_DIR ${CMAKE_BINARY_DIR}/libpng-1.5.12)
-  SET(LIBPNG_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/libpng-1.5.12.tar.gz")
+  SET(LIBPNG_URL "http://www.orthanc-server.com/downloads/third-party/libpng-1.5.12.tar.gz")
   SET(LIBPNG_MD5 "8ea7f60347a306c5faf70b977fa80e28")
 
   DownloadPackage(${LIBPNG_MD5} ${LIBPNG_URL} "${LIBPNG_SOURCES_DIR}")
@@ -46,7 +46,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPNG)
     -DPNG_IMPEXP=
     )
 
-  source_group(ThirdParty\\Libpng REGULAR_EXPRESSION ${LIBPNG_SOURCES_DIR}/.*)
+  source_group(ThirdParty\\libpng REGULAR_EXPRESSION ${LIBPNG_SOURCES_DIR}/.*)
 
 else()
   include(FindPNG)
diff --git a/Resources/CMake/LuaConfiguration.cmake b/Resources/CMake/LuaConfiguration.cmake
index 40bda1e..b88a3f1 100644
--- a/Resources/CMake/LuaConfiguration.cmake
+++ b/Resources/CMake/LuaConfiguration.cmake
@@ -1,7 +1,7 @@
 if (STATIC_BUILD OR NOT USE_SYSTEM_LUA)
   SET(LUA_SOURCES_DIR ${CMAKE_BINARY_DIR}/lua-5.1.5)
   SET(LUA_MD5 "2e115fe26e435e33b0d5c022e4490567")
-  SET(LUA_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/lua-5.1.5.tar.gz")
+  SET(LUA_URL "http://www.orthanc-server.com/downloads/third-party/lua-5.1.5.tar.gz")
 
   DownloadPackage(${LUA_MD5} ${LUA_URL} "${LUA_SOURCES_DIR}")
 
diff --git a/Resources/CMake/MongooseConfiguration.cmake b/Resources/CMake/MongooseConfiguration.cmake
index c451981..4ef44f2 100644
--- a/Resources/CMake/MongooseConfiguration.cmake
+++ b/Resources/CMake/MongooseConfiguration.cmake
@@ -11,7 +11,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_MONGOOSE)
     # Use Mongoose 3.1
     DownloadPackage(
       "e718fc287b4eb1bd523be3fa00942bb0"
-      "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/mongoose-3.1.tgz"
+      "http://www.orthanc-server.com/downloads/third-party/mongoose-3.1.tgz"
       "${MONGOOSE_SOURCES_DIR}")
     
     add_definitions(-DMONGOOSE_USE_CALLBACKS=0)
@@ -21,7 +21,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_MONGOOSE)
     # Use Mongoose 3.8
     DownloadPackage(
       "7e3296295072792cdc3c633f9404e0c3"
-      "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/mongoose-3.8.tgz"
+      "http://www.orthanc-server.com/downloads/third-party/mongoose-3.8.tgz"
       "${MONGOOSE_SOURCES_DIR}")
     
     add_definitions(-DMONGOOSE_USE_CALLBACKS=1)
diff --git a/Resources/CMake/OpenSslConfiguration.cmake b/Resources/CMake/OpenSslConfiguration.cmake
index 6e7a995..5652e59 100644
--- a/Resources/CMake/OpenSslConfiguration.cmake
+++ b/Resources/CMake/OpenSslConfiguration.cmake
@@ -4,7 +4,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL)
   # not always properly handled when uncompressing on Windows.
 
   SET(OPENSSL_SOURCES_DIR ${CMAKE_BINARY_DIR}/openssl-1.0.2d)
-  SET(OPENSSL_URL "www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/openssl-1.0.2d.zip")
+  SET(OPENSSL_URL "http://www.orthanc-server.com/downloads/third-party/openssl-1.0.2d.zip")
   SET(OPENSSL_MD5 "4b2ac15fc6db17f3dadc54482d3eee85")
 
   if (IS_DIRECTORY "${OPENSSL_SOURCES_DIR}")
@@ -191,9 +191,10 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL)
     ${OPENSSL_SOURCES_DIR}/crypto/x509/verify_extra_test.c
     ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3prin.c
     ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3nametest.c
-    ${OPENSSL_SOURCES_DIR}/crypto/ssl/heartbeat_test.c
     ${OPENSSL_SOURCES_DIR}/crypto/constant_time_test.c
     ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256_table.c
+
+    ${OPENSSL_SOURCES_DIR}/ssl/heartbeat_test.c
     )
 
 
@@ -215,6 +216,8 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL)
     endif()
   endif()
 
+  source_group(ThirdParty\\OpenSSL REGULAR_EXPRESSION ${OPENSSL_SOURCES_DIR}/.*)
+
 else()
   include(FindOpenSSL)
 
diff --git a/Resources/CMake/PugixmlConfiguration.cmake b/Resources/CMake/PugixmlConfiguration.cmake
index 4094fa3..4d57b12 100644
--- a/Resources/CMake/PugixmlConfiguration.cmake
+++ b/Resources/CMake/PugixmlConfiguration.cmake
@@ -1,10 +1,10 @@
 if (USE_PUGIXML)
-  add_definitions(-DORTHANC_PUGIXML_ENABLED=1)
+  add_definitions(-DORTHANC_ENABLE_PUGIXML=1)
 
   if (STATIC_BUILD OR NOT USE_SYSTEM_PUGIXML)
     set(PUGIXML_SOURCES_DIR ${CMAKE_BINARY_DIR}/pugixml-1.4)
     set(PUGIXML_MD5 "7c56c91cfe3ecdee248a8e4892ef5781")
-    set(PUGIXML_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/pugixml-1.4.tar.gz")
+    set(PUGIXML_URL "http://www.orthanc-server.com/downloads/third-party/pugixml-1.4.tar.gz")
 
     DownloadPackage(${PUGIXML_MD5} ${PUGIXML_URL} "${PUGIXML_SOURCES_DIR}")
 
@@ -26,6 +26,8 @@ if (USE_PUGIXML)
     link_libraries(pugixml)
   endif()
 
+  source_group(ThirdParty\\pugixml REGULAR_EXPRESSION ${PUGIXML_SOURCES_DIR}/.*)
+
 else()
-  add_definitions(-DORTHANC_PUGIXML_ENABLED=0)
+  add_definitions(-DORTHANC_ENABLE_PUGIXML=0)
 endif()
diff --git a/Resources/CMake/SQLiteConfiguration.cmake b/Resources/CMake/SQLiteConfiguration.cmake
index c6b446a..e15a6e0 100644
--- a/Resources/CMake/SQLiteConfiguration.cmake
+++ b/Resources/CMake/SQLiteConfiguration.cmake
@@ -17,7 +17,7 @@ endif()
 if (SQLITE_STATIC)
   SET(SQLITE_SOURCES_DIR ${CMAKE_BINARY_DIR}/sqlite-amalgamation-3071300)
   SET(SQLITE_MD5 "5fbeff9645ab035a1f580e90b279a16d")
-  SET(SQLITE_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/sqlite-amalgamation-3071300.zip")
+  SET(SQLITE_URL "http://www.orthanc-server.com/downloads/third-party/sqlite-amalgamation-3071300.zip")
 
   DownloadPackage(${SQLITE_MD5} ${SQLITE_URL} "${SQLITE_SOURCES_DIR}")
 
diff --git a/Resources/CMake/ZlibConfiguration.cmake b/Resources/CMake/ZlibConfiguration.cmake
index e1940c7..4487c1e 100644
--- a/Resources/CMake/ZlibConfiguration.cmake
+++ b/Resources/CMake/ZlibConfiguration.cmake
@@ -1,6 +1,6 @@
 if (STATIC_BUILD OR NOT USE_SYSTEM_ZLIB)
   SET(ZLIB_SOURCES_DIR ${CMAKE_BINARY_DIR}/zlib-1.2.7)
-  SET(ZLIB_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/zlib-1.2.7.tar.gz")
+  SET(ZLIB_URL "http://www.orthanc-server.com/downloads/third-party/zlib-1.2.7.tar.gz")
   SET(ZLIB_MD5 "60df6a37c56e7c1366cca812414f7b85")
 
   DownloadPackage(${ZLIB_MD5} ${ZLIB_URL} "${ZLIB_SOURCES_DIR}")
@@ -27,10 +27,10 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_ZLIB)
     ${ZLIB_SOURCES_DIR}/zutil.c
     )
 
+  source_group(ThirdParty\\zlib REGULAR_EXPRESSION ${ZLIB_SOURCES_DIR}/.*)
+
 else()
   include(FindZLIB)
   include_directories(${ZLIB_INCLUDE_DIRS})
   link_libraries(${ZLIB_LIBRARIES})
 endif()
-
-source_group(ThirdParty\\ZLib REGULAR_EXPRESSION ${ZLIB_SOURCES_DIR}/.*)
diff --git a/Resources/Configuration.json b/Resources/Configuration.json
index 6ba93c6..43975bf 100644
--- a/Resources/Configuration.json
+++ b/Resources/Configuration.json
@@ -87,10 +87,11 @@
   "DicomPort" : 4242,
 
   // The default encoding that is assumed for DICOM files without
-  // "SpecificCharacterSet" DICOM tag. The allowed values are "Ascii",
-  // "Utf8", "Latin1", "Latin2", "Latin3", "Latin4", "Latin5",
-  // "Cyrillic", "Windows1251", "Arabic", "Greek", "Hebrew", "Thai",
-  // "Japanese", and "Chinese".
+  // "SpecificCharacterSet" DICOM tag, and that is used when answering
+  // C-Find requests (including worklists). The allowed values are
+  // "Ascii", "Utf8", "Latin1", "Latin2", "Latin3", "Latin4",
+  // "Latin5", "Cyrillic", "Windows1251", "Arabic", "Greek", "Hebrew",
+  // "Thai", "Japanese", and "Chinese".
   "DefaultEncoding" : "Latin1",
 
   // The transfer syntaxes that are accepted by Orthanc C-Store SCP
@@ -106,6 +107,11 @@
   // SOP classes (aka. "promiscuous mode")
   "UnknownSopClassAccepted"            : false,
 
+  // Set the timeout (in seconds) after which the DICOM associations
+  // are closed by the Orthanc SCP (server) if no further DIMSE
+  // command is received from the SCU (client).
+  "DicomScpTimeout" : 30,
+
 
 
   /**
@@ -158,6 +164,11 @@
     // "clearcanvas" : [ "CLEARCANVAS", "192.168.1.1", 104, "ClearCanvas" ]
   },
 
+  // The timeout (in seconds) after which the DICOM associations are
+  // considered as closed by the Orthanc SCU (client) if the remote
+  // DICOM SCP (server) does not answer.
+  "DicomScuTimeout" : 10,
+
   // The list of the known Orthanc peers
   "OrthancPeers" : {
     /**
@@ -216,7 +227,8 @@
 
   // Dictionary of symbolic names for the user-defined metadata. Each
   // entry must map an unique string to an unique number between 1024
-  // and 65535.
+  // and 65535. Reserved values:
+  //  - The Orthanc whole-slide imaging plugin uses metadata 4200
   "UserMetadata" : {
     // "Sample" : 1024
   },
@@ -302,18 +314,33 @@
      }
    **/
   
-  // If set to "true", Orthanc will handle "SOP Classes in Study"
-  // (0008,0062) in C-FIND requests. This option is turned off by
-  // default, as it requires intensive accesses to the hard drive.
+  // If set to "true", Orthanc will still handle "SOP Classes in
+  // Study" (0008,0062) in C-FIND requests, even if the "SOP Class
+  // UID" metadata is not available in the database (which is the case
+  // if the DB was previously used by Orthanc <= 1.1.0). This option
+  // is turned off by default, as it requires intensive accesses to
+  // the hard drive.
   "AllowFindSopClassesInStudy" : false,
 
+  // If set to "false", Orthanc will not load its default dictionary
+  // of private tags. This might be necessary if you cannot import a
+  // DICOM file encoded using the Implicit VR Endian transfer syntax,
+  // and containing private tags: Such an import error might stem from
+  // a bad dictionary. You can still list your private tags of
+  // interest in the "Dictionary" configuration option below.
+  "LoadPrivateDictionary" : true,
+
   // Register a new tag in the dictionary of DICOM tags that are known
   // to Orthanc. Each line must contain the tag (formatted as 2
   // hexadecimal numbers), the value representation (2 upcase
   // characters), a nickname for the tag, possibly the minimum
-  // multiplicity (> 0 with defaults to 1), and possibly the maximum
-  // multiplicity (0 means arbitrary multiplicity, defaults to 1).
+  // multiplicity (> 0 with defaults to 1), possibly the maximum
+  // multiplicity (0 means arbitrary multiplicity, defaults to 1), and
+  // possibly the Private Creator (for private tags).
   "Dictionary" : {
     // "0014,1020" : [ "DA", "ValidationExpiryDate", 1, 1 ]
+    // "00e1,10c2" : [ "UI", "PET-CT Multi Modality Name", 1, 1, "ELSCINT1" ]
+    // "7053,1003" : [ "ST", "Original Image Filename", 1, 1, "Philips PET Private Group" ]
+    // "2001,5f" : [ "SQ", "StackSequence", 1, 1, "Philips Imaging DD 001" ]
   }
 }
diff --git a/Resources/DicomConformanceStatement.txt b/Resources/DicomConformanceStatement.txt
index af8c95d..939e9f5 100644
--- a/Resources/DicomConformanceStatement.txt
+++ b/Resources/DicomConformanceStatement.txt
@@ -203,7 +203,7 @@ Orthanc supports the following SOP Classes as an SCU for C-Move:
 Transfer Syntaxes
 -----------------
 
-Orthanc will accept and negociate presentation contexts for all of the
+Orthanc will accept and negotiate presentation contexts for all of the
 abovementioned supported SOP Classes using any of the following
 transfer syntaxes:
 
diff --git a/Resources/EmbedResources.py b/Resources/EmbedResources.py
index d914d15..ad5cf61 100755
--- a/Resources/EmbedResources.py
+++ b/Resources/EmbedResources.py
@@ -159,6 +159,10 @@ header.write("""
 #include <string>
 #include <list>
 
+#if defined(_MSC_VER)
+#  pragma warning(disable: 4065)  // "Switch statement contains 'default' but no 'case' labels"
+#endif
+
 namespace %s
 {
   namespace EmbeddedResources
diff --git a/Resources/ErrorCodes.json b/Resources/ErrorCodes.json
index f6ac2a7..083df34 100644
--- a/Resources/ErrorCodes.json
+++ b/Resources/ErrorCodes.json
@@ -32,7 +32,7 @@
   {
     "Code": 4, 
     "Name": "NotEnoughMemory", 
-    "Description": "Not enough memory"
+    "Description": "The server hosting Orthanc is running out of memory"
   }, 
   {
     "Code": 5, 
@@ -195,6 +195,11 @@
     "HttpStatus": 406, 
     "Name": "NotAcceptable", 
     "Description": "Cannot send a response which is acceptable according to the Accept HTTP header"
+  }, 
+  {
+    "Code": 35, 
+    "Name": "NullPointer", 
+    "Description": "Cannot handle a NULL pointer"
   },
 
 
diff --git a/Resources/Orthanc.doxygen b/Resources/Orthanc.doxygen
index 9e2fd0e..b99ccb9 100644
--- a/Resources/Orthanc.doxygen
+++ b/Resources/Orthanc.doxygen
@@ -1,110 +1,129 @@
-# Doxyfile 1.8.1.2
+# Doxyfile 1.8.7
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project.
 #
-# All text after a hash (#) is considered a comment and will be ignored.
+# 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 (" ").
+# 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.
+# 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 sequence of words) that should
-# identify the project. Note that if you do not use Doxywizard you need
-# to put quotes around the project name if it contains spaces.
+# 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           = Orthanc
 
-# 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.
+# 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.
+# 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          = "Internal documentation of Orthanc"
 
-# 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.
+# 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           = @CMAKE_SOURCE_DIR@/Resources/OrthancLogoDocumentation.png
 
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
+# 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       = OrthancInternalDocumentation
 
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
+# 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.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+# 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 (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
+# 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 (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# 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" "the"
+# 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
+# doxygen will generate a detailed section even if there is only a brief
 # description.
+# The default value is: NO.
 
 ALWAYS_DETAILED_SEC    = NO
 
@@ -112,169 +131,207 @@ ALWAYS_DETAILED_SEC    = NO
 # 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 then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
+# 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        = NO
 
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
+# 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 include paths that
-# are normally passed to the compiler using the -I flag.
+# 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 if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
+# 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
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
+# 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 comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
+# 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 behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
+# 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 (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
+# 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.
+# 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.
+# 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               = 8
 
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
+# 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.
+# 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.
+# 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
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
+# 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 only. Doxygen will then generate output that is more tailored for
-# 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.
+# 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, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. 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 that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+# 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 MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
-# comments according to the Markdown format, which allows for more readable
+# 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 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); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
+# 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    = YES
 
 # 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 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.
+# 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 (the default)
-# will make doxygen 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.
+# 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
 
@@ -282,67 +339,61 @@ IDL_PROPERTY_SUPPORT   = YES
 # 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 (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
+# 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).
+# 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 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 (the default),
-# structs, classes, and unions are shown on a separate page (for HTML and Man
-# pages) or section (for LaTeX and RTF).
+# 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 is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
+# 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
+# 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 SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
-
-SYMBOL_CACHE_SIZE      = 0
-
-# Similar to the SYMBOL_CACHE_SIZE 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 appear 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.
+# 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
 
@@ -351,340 +402,391 @@ LOOKUP_CACHE_SIZE      = 0
 #---------------------------------------------------------------------------
 
 # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+# 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            = YES
 
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
+# 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.
+# 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.
+# 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.
+# 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 (the default) only methods in the interface are included.
+# 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 namespaces are hidden.
+# '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 of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
+# 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 (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
+# 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 (the default) these declarations will be included in the
-# documentation.
+# 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 (the default) these blocks will be appended to the
-# function's detailed documentation block.
+# 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 (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
+# 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
+# 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       = YES
 
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
+# 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 (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
+# 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 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.
+# 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 (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
+# 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 (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
+# 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 documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
+# 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 default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to 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 default)
-# the group names will appear in their defined order.
+# 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 default), the class list will be sorted only by class name,
-# not including the namespace part.
+# 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.
+# 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.
+# 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 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 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 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 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 sectionname ... \endif.
+# 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
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
+# 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.
+# 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 is 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 is 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. See the manual for examples.
+# 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.
+# 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 references data. This must be a list of .bib files. The
-# .bib extension is automatically appended if omitted. Using this command
-# 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.
+# 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. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
 
 CITE_BIB_FILES         =
 
 #---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
+# Configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
 
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
+# 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 by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
+# 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 WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
+# 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 WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
+# 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
 
-# The 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 (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
+# 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 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 stderr.
+# 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
+# Configuration options related to the input files
 #---------------------------------------------------------------------------
 
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
+# 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                  = @CMAKE_SOURCE_DIR@/Core \
                          @CMAKE_SOURCE_DIR@/OrthancServer
 
 # This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
+# 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 pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.for *.vhd *.vhdl
+# 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          = *.h
 
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
+# 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.
 
@@ -693,14 +795,16 @@ 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/*
+# 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       =
 
@@ -709,755 +813,1076 @@ EXCLUDE_PATTERNS       =
 # 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        = Orthanc::Internals
 
-# 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).
+# 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 tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
 
 EXAMPLE_PATTERNS       =
 
 # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
+# 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 image that are included in the documentation (see
-# the \image command).
+# 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.
+# 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
-# info on how filters are used. If FILTER_PATTERNS is empty or if
-# non of the patterns match the file name, INPUT_FILTER is applied.
+# 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 be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# 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 option only has effect when
-# FILTER_SOURCE_FILES is enabled.
+# 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
+# Configuration options related to source browsing
 #---------------------------------------------------------------------------
 
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
+# 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 and classes directly in the documentation.
+# 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 (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C, C++ and Fortran comments will always remain visible.
+# 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.
+# 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.
+# 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 (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
+# 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 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.
+# 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 to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
+# 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
+# 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.
+# 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
 
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
+# 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 one or more prefixes that
-# should be ignored while generating the index headers.
+# 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
+# Configuration options related to the HTML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate 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. If left blank `html' will be used as the default path.
+# 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            = doc
 
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
+# 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 personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header. Note that when using a custom header you are responsible
-#  for the proper inclusion of any scripts and style sheets that doxygen
-# needs, which is dependent on the configuration options used.
-# It is advised to generate a default header using "doxygen -w html
-# header.html footer.html stylesheet.css YourConfigFile" and then modify
-# that header. Note that the header is subject to change so you typically
-# have to redo this when upgrading to a newer version of doxygen or when
-# changing the value of configuration settings such as GENERATE_TREEVIEW!
+# 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 personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
+# 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 the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# style sheet in the HTML output directory as well, or it will be erased!
+# 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 an additional user-
+# defined cascading style sheet that is 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 file to the output directory. 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.
+# $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 style sheet 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.
-# The allowed range is 0 to 359.
+# 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.
+# 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.
+# 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.
+# 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         = NO
 
 # 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.
+# 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, 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
+# 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
 
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
+# 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"
 
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
+# 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
 
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# 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 GENERATE_PUBLISHER_NAME tag identifies the documentation 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, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
+# 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
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
+# 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               =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
+# 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           =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
+# 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
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
+# 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     =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
+# 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 contents of the HTML help documentation and to the tree view.
+# 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.
+# 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.
+# 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
-# http://doc.trolltech.com/qthelpproject.html#namespace
+# 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
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+# 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 QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
+# 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_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
+# 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.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
+# 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  =
 
-# If the GENERATE_QHP tag is set to YES, 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.
+# 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, which together with the HTML files, 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.
+# 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.
+# 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
 
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
-# at top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it. Since the tabs have the same information as the
-# navigation tree you can set this option to NO if you already set
-# GENERATE_TREEVIEW to YES.
+# 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.
-# Since the tree basically has the same information as the tab index you
-# could consider to set DISABLE_INDEX to NO when enabling this option.
+# 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
-# (range [0,1..20]) 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.
+# 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   = 1
 
-# 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.
+# 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.
+# 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. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
+# 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 before the changes have effect.
+# 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.
+# 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 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.
+# 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://www.mathjax.org/mathjax
 
-# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
-# names that should be enabled during MathJax rendering.
+# 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     =
 
-# 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.
+# 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 PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvantages are that it is more difficult to setup
-# and does not have live searching capabilities.
+# 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
+# Configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate 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. If left blank `latex' will be used as the default path.
+# 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. If left blank `latex' will be used as the default command name.
-# 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.
+# 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. If left blank `makeindex' will be used as the
-# default command name.
+# 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.
+# 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, letter, legal and
-# executive. If left blank a4wide will be used.
+# 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 to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
+# 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. Notice: only use this tag if you know what you are doing!
+# 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. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# 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. Notice: only use this tag if you know what you are doing!
+# 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.
+#
+# 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           =
 
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
+# 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, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
+# If the LATEX_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.
+# 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 LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
+# 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 LATEX_SOURCE_CODE 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.
+# 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. The default style is "plain". See
-# http://en.wikipedia.org/wiki/BibTeX for more info.
+# 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
+# Configuration options related to the RTF output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
+# 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. If left blank `rtf' will be used as the default path.
+# 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.
+# 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 other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
+# 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 style sheet 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.
+# 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.
+# 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
+# Configuration options related to the man page output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
+# 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. If left blank `man' will be used as the default path.
+# 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 (default is the subroutine's section .3)
+# 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
 
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
+# 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
+# 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.
+# 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. If left blank `xml' will be used as the default path.
+# 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
 
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
+# 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_SCHEMA             =
+XML_PROGRAMLISTING     = YES
 
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
 
-XML_DTD                =
+# 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.
 
-# 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.
+GENERATE_DOCBOOK       = NO
 
-XML_PROGRAMLISTING     = YES
+# 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
 
 #---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
+# Configuration options for the AutoGen Definitions output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
+# 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
+# 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.
+# 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.
+# 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.
+# 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.
+# 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 =
 
@@ -1465,106 +1890,128 @@ PERLMOD_MAKEVAR_PREFIX =
 # Configuration options related to the preprocessor
 #---------------------------------------------------------------------------
 
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
+# 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 (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to 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.
+# 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 default) the includes files
-# pointed to by INCLUDE_PATH will be searched when a #include is found.
+# 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.
+# 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.
+# 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
-# 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.
+# 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.
+# 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 (the default) 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, because these will confuse the parser if not removed.
+# 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::additions related to external references
+# Configuration options related to external references
 #---------------------------------------------------------------------------
 
-# The TAGFILES option can be used to specify one or more tagfiles. 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:
-#
+# 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. Note that each tag file must have a unique name (where the name does
-# NOT include the path). If a tag file is not located in the directory in which
-# doxygen is run, you must also specify the path to the tagfile here.
+# 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.
+# 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 classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
+# 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.
+# 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').
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
 
 PERL_PATH              = /usr/bin/perl
 
@@ -1572,222 +2019,295 @@ PERL_PATH              = /usr/bin/perl
 # Configuration options related to the dot tool
 #---------------------------------------------------------------------------
 
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
+# 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
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
 # documentation. The MSCGEN_PATH tag allows you to specify the directory where
 # the mscgen tool resides. If left empty the tool is assumed to be found in the
 # default search path.
 
 MSCGEN_PATH            =
 
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
+# 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, 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)
+# 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: YES.
 
 HAVE_DOT               = NO
 
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) 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.
+# 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
 
-# By default doxygen will use the Helvetica font for all dot files that
-# doxygen generates. When you want a differently looking font 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.
+# When you want a differently looking font n 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 of the font of dot graphs.
-# The default size is 10pt.
+# 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 Helvetica font.
-# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
-# set the path where dot can find it.
+# 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 and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# CLASS_DIAGRAMS tag to NO.
+# 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 and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
+# 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 and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
+# 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
-# managable. Set this to 0 for no limit. Note that the threshold may be
-# exceeded by 50% before the limit is enforced.
+# 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 set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
+# 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 ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
+# 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 ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
+# 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 and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
+# 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 and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
+# 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 and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
+# 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 and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
+# 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. Possible values are svg, png, jpg, or gif.
-# If left blank png will be used. 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).
+# 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, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd 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. 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.
+#
+# 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 tag DOT_PATH can be used to specify the path where the dot tool can be
+# 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).
+# 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).
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
 
 MSCFILE_DIRS           =
 
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# 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           =
+
+# 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
+# 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).
+# 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.
+# 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      = YES
 
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
+# 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 (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
+# 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/Resources/OrthancPlugin.doxygen b/Resources/OrthancPlugin.doxygen
index 0b68168..7a943b9 100644
--- a/Resources/OrthancPlugin.doxygen
+++ b/Resources/OrthancPlugin.doxygen
@@ -1,110 +1,129 @@
-# Doxyfile 1.8.1.2
+# Doxyfile 1.8.7
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project.
 #
-# All text after a hash (#) is considered a comment and will be ignored.
+# 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 (" ").
+# 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.
+# 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 sequence of words) that should
-# identify the project. Note that if you do not use Doxywizard you need
-# to put quotes around the project name if it contains spaces.
+# 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           = "Orthanc Plugin SDK"
 
-# 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.
+# 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         =
+PROJECT_NUMBER         = @ORTHANC_VERSION@
 
 # 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.
+# 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          = "Documentation of the plugin interface of Orthanc"
 
-# 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.
+# 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           = @CMAKE_SOURCE_DIR@/Resources/OrthancLogoDocumentation.png
 
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
+# 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       = OrthancPluginDocumentation
 
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
+# 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.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+# 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 (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
+# 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 (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# 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           = NO
 
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
+# 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
+# doxygen will generate a detailed section even if there is only a brief
 # description.
+# The default value is: NO.
 
 ALWAYS_DETAILED_SEC    = NO
 
@@ -112,169 +131,207 @@ ALWAYS_DETAILED_SEC    = NO
 # 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 then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
+# 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        = NO
 
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
+# 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 include paths that
-# are normally passed to the compiler using the -I flag.
+# 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 if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
+# 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
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
+# 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 comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
+# 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 behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
+# 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 (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
+# 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.
+# 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.
+# 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               = 8
 
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
+# 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.
+# 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.
+# 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
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
+# 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 only. Doxygen will then generate output that is more tailored for
-# 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.
+# 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, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. 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 that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+# 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 MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
-# comments according to the Markdown format, which allows for more readable
+# 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 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); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
+# 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    = YES
 
 # 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 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.
+# 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 (the default)
-# will make doxygen 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.
+# 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
 
@@ -282,67 +339,61 @@ IDL_PROPERTY_SUPPORT   = YES
 # 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 (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
+# 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).
+# 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 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 (the default),
-# structs, classes, and unions are shown on a separate page (for HTML and Man
-# pages) or section (for LaTeX and RTF).
+# 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 is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
+# 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
+# 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 SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
-
-SYMBOL_CACHE_SIZE      = 0
-
-# Similar to the SYMBOL_CACHE_SIZE 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 appear 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.
+# 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
 
@@ -351,341 +402,392 @@ LOOKUP_CACHE_SIZE      = 0
 #---------------------------------------------------------------------------
 
 # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+# 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.
+# 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.
+# 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.
+# 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.
+# 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 (the default) only methods in the interface are included.
+# 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 namespaces are hidden.
+# '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 of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
+# 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 (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
+# 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 (the default) these declarations will be included in the
-# documentation.
+# 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  = YES
 
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
+# 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 (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
+# 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
+# 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       = YES
 
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
+# 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 (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
+# 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 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.
+# 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 (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
+# 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 (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
+# 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 documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
+# 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 default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to 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 default)
-# the group names will appear in their defined order.
+# 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 default), the class list will be sorted only by class name,
-# not including the namespace part.
+# 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.
+# 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.
+# 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 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 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 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 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 sectionname ... \endif.
+# 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
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
+# 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  = 0
 
-# 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.
+# 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 is 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 is 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. See the manual for examples.
+# 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.
+# 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 references data. This must be a list of .bib files. The
-# .bib extension is automatically appended if omitted. Using this command
-# 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.
+# 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. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
 
 CITE_BIB_FILES         =
 
 #---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
+# Configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
 
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
+# 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 by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
+# 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 WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
+# 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 WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
+# 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
 
-# The 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 (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
+# 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       = YES
 
-# 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 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 stderr.
+# 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
+# Configuration options related to the input files
 #---------------------------------------------------------------------------
 
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
+# 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                  = @CMAKE_SOURCE_DIR@/Plugins/Include/orthanc/OrthancCPlugin.h \
                          @CMAKE_SOURCE_DIR@/Plugins/Include/orthanc/OrthancCDatabasePlugin.h \
                          @CMAKE_SOURCE_DIR@/Plugins/Include/orthanc/OrthancCppDatabasePlugin.h
 
 # This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
+# 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 pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.for *.vhd *.vhdl
+# 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          = *.h
 
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
+# 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.
 
@@ -694,14 +796,16 @@ 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/*
+# 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       =
 
@@ -710,755 +814,1077 @@ EXCLUDE_PATTERNS       =
 # 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        = _OrthancPlugin* OrthancPluginGetName
+EXCLUDE_SYMBOLS        = _OrthancPlugin* \
+                         OrthancPluginGetName
 
-# 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).
+# 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 tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
 
 EXAMPLE_PATTERNS       =
 
 # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
+# 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 image that are included in the documentation (see
-# the \image command).
+# 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.
+# 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
-# info on how filters are used. If FILTER_PATTERNS is empty or if
-# non of the patterns match the file name, INPUT_FILTER is applied.
+# 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 be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# 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 option only has effect when
-# FILTER_SOURCE_FILES is enabled.
+# 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
+# Configuration options related to source browsing
 #---------------------------------------------------------------------------
 
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
+# 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 and classes directly in the documentation.
+# 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 (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C, C++ and Fortran comments will always remain visible.
+# 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.
+# 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.
+# 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 (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
+# 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 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.
+# 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 to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
+# 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
+# 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.
+# 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
 
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
+# 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 one or more prefixes that
-# should be ignored while generating the index headers.
+# 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
+# Configuration options related to the HTML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate 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. If left blank `html' will be used as the default path.
+# 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            = doc
 
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
+# 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 personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header. Note that when using a custom header you are responsible
-#  for the proper inclusion of any scripts and style sheets that doxygen
-# needs, which is dependent on the configuration options used.
-# It is advised to generate a default header using "doxygen -w html
-# header.html footer.html stylesheet.css YourConfigFile" and then modify
-# that header. Note that the header is subject to change so you typically
-# have to redo this when upgrading to a newer version of doxygen or when
-# changing the value of configuration settings such as GENERATE_TREEVIEW!
+# 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 personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
+# 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 the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# style sheet in the HTML output directory as well, or it will be erased!
+# 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 an additional user-
+# defined cascading style sheet that is 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 file to the output directory. 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.
+# $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 style sheet 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.
-# The allowed range is 0 to 359.
+# 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.
+# 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.
+# 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.
+# 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         = NO
 
 # 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.
+# 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, 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
+# 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
 
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
+# 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"
 
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
+# 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
 
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# 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 GENERATE_PUBLISHER_NAME tag identifies the documentation 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, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
+# 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
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
+# 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               =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
+# 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           =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
+# 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
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
+# 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     =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
+# 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 contents of the HTML help documentation and to the tree view.
+# 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.
+# 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.
+# 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
-# http://doc.trolltech.com/qthelpproject.html#namespace
+# 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
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+# 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 QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
+# 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_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
+# 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.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
+# 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  =
 
-# If the GENERATE_QHP tag is set to YES, 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.
+# 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, which together with the HTML files, 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.
+# 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.
+# 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
 
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
-# at top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it. Since the tabs have the same information as the
-# navigation tree you can set this option to NO if you already set
-# GENERATE_TREEVIEW to YES.
+# 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.
-# Since the tree basically has the same information as the tab index you
-# could consider to set DISABLE_INDEX to NO when enabling this option.
+# 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
-# (range [0,1..20]) 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.
+# 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   = 1
 
-# 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.
+# 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.
+# 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. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
+# 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 before the changes have effect.
+# 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.
+# 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 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.
+# 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://www.mathjax.org/mathjax
 
-# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
-# names that should be enabled during MathJax rendering.
+# 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     =
 
-# 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.
+# 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           = NO
 
 # When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvantages are that it is more difficult to setup
-# and does not have live searching capabilities.
+# 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
+# Configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate 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. If left blank `latex' will be used as the default path.
+# 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. If left blank `latex' will be used as the default command name.
-# 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.
+# 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. If left blank `makeindex' will be used as the
-# default command name.
+# 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.
+# 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, letter, legal and
-# executive. If left blank a4wide will be used.
+# 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 to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
+# 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. Notice: only use this tag if you know what you are doing!
+# 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. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# 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. Notice: only use this tag if you know what you are doing!
+# 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.
+#
+# 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           =
 
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
+# 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, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
+# If the LATEX_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.
+# 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 LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
+# 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 LATEX_SOURCE_CODE 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.
+# 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. The default style is "plain". See
-# http://en.wikipedia.org/wiki/BibTeX for more info.
+# 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
+# Configuration options related to the RTF output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
+# 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. If left blank `rtf' will be used as the default path.
+# 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.
+# 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 other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
+# 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 style sheet 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.
+# 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.
+# 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
+# Configuration options related to the man page output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
+# 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. If left blank `man' will be used as the default path.
+# 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 (default is the subroutine's section .3)
+# 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
 
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
+# 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
+# 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.
+# 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. If left blank `xml' will be used as the default path.
+# 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
 
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
+# 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_SCHEMA             =
+XML_PROGRAMLISTING     = YES
 
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
 
-XML_DTD                =
+# 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.
 
-# 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.
+GENERATE_DOCBOOK       = NO
 
-XML_PROGRAMLISTING     = YES
+# 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
 
 #---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
+# Configuration options for the AutoGen Definitions output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
+# 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
+# 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.
+# 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.
+# 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.
+# 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.
+# 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 =
 
@@ -1466,106 +1892,128 @@ PERLMOD_MAKEVAR_PREFIX =
 # Configuration options related to the preprocessor
 #---------------------------------------------------------------------------
 
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
+# 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 (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to 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        = YES
 
-# 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.
+# 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     = YES
 
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# pointed to by INCLUDE_PATH will be searched when a #include is found.
+# 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.
+# 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.
+# 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
-# 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.
+# 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             = ORTHANC_PLUGIN_INLINE=
 
-# 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.
+# 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 (the default) 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, because these will confuse the parser if not removed.
+# 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::additions related to external references
+# Configuration options related to external references
 #---------------------------------------------------------------------------
 
-# The TAGFILES option can be used to specify one or more tagfiles. 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:
-#
+# 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. Note that each tag file must have a unique name (where the name does
-# NOT include the path). If a tag file is not located in the directory in which
-# doxygen is run, you must also specify the path to the tagfile here.
+# 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.
+# 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 classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
+# 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.
+# 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').
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
 
 PERL_PATH              = /usr/bin/perl
 
@@ -1573,222 +2021,295 @@ PERL_PATH              = /usr/bin/perl
 # Configuration options related to the dot tool
 #---------------------------------------------------------------------------
 
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
+# 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
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
 # documentation. The MSCGEN_PATH tag allows you to specify the directory where
 # the mscgen tool resides. If left empty the tool is assumed to be found in the
 # default search path.
 
 MSCGEN_PATH            =
 
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
+# 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, 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)
+# 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: YES.
 
 HAVE_DOT               = NO
 
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) 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.
+# 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
 
-# By default doxygen will use the Helvetica font for all dot files that
-# doxygen generates. When you want a differently looking font 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.
+# When you want a differently looking font n 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 of the font of dot graphs.
-# The default size is 10pt.
+# 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 Helvetica font.
-# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
-# set the path where dot can find it.
+# 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 and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# CLASS_DIAGRAMS tag to NO.
+# 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 and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
+# 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 and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
+# 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
-# managable. Set this to 0 for no limit. Note that the threshold may be
-# exceeded by 50% before the limit is enforced.
+# 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 set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
+# 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 ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
+# 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 ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
+# 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 and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
+# 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 and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
+# 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 and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
+# 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 and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
+# 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. Possible values are svg, png, jpg, or gif.
-# If left blank png will be used. 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).
+# 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, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd 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. 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.
+#
+# 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 tag DOT_PATH can be used to specify the path where the dot tool can be
+# 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).
+# 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).
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
 
 MSCFILE_DIRS           =
 
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# 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           =
+
+# 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
+# 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).
+# 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.
+# 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      = YES
 
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
+# 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 (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
+# 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/Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch b/Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch
new file mode 100644
index 0000000..321f810
--- /dev/null
+++ b/Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch
@@ -0,0 +1,29 @@
+diff -urEb dcmtk-3.6.0.orig/dcmnet/libsrc/dulparse.cc dcmtk-3.6.0/dcmnet/libsrc/dulparse.cc
+--- dcmtk-3.6.0.orig/dcmnet/libsrc/dulparse.cc	2010-12-01 09:26:36.000000000 +0100
++++ dcmtk-3.6.0/dcmnet/libsrc/dulparse.cc	2016-12-02 15:58:49.930540033 +0100
+@@ -393,6 +393,8 @@
+                     return cond;
+ 
+                 buf += length;
++                if (presentationLength < length)
++                  return EC_MemoryExhausted;
+                 presentationLength -= length;
+                 DCMNET_TRACE("Successfully parsed Abstract Syntax");
+                 break;
+@@ -404,12 +406,16 @@
+                 cond = LST_Enqueue(&context->transferSyntaxList, (LST_NODE*)subItem);
+                 if (cond.bad()) return cond;
+                 buf += length;
++                if (presentationLength < length)
++                  return EC_MemoryExhausted;
+                 presentationLength -= length;
+                 DCMNET_TRACE("Successfully parsed Transfer Syntax");
+                 break;
+             default:
+                 cond = parseDummy(buf, &length, presentationLength);
+                 buf += length;
++                if (presentationLength < length)
++                  return EC_MemoryExhausted;
+                 presentationLength -= length;
+                 break;
+             }
diff --git a/Resources/Patches/dcmtk-3.6.1-private.dic b/Resources/Patches/dcmtk-3.6.1-private.dic
new file mode 100644
index 0000000..880753f
--- /dev/null
+++ b/Resources/Patches/dcmtk-3.6.1-private.dic
@@ -0,0 +1,3040 @@
+#
+#  Copyright (C) 1994-2013, OFFIS e.V.
+#  All rights reserved.  See COPYRIGHT file for details.
+#
+#  This software and supporting documentation were developed by
+#
+#    OFFIS e.V.
+#    R&D Division Health
+#    Escherweg 2
+#    D-26121 Oldenburg, Germany
+#
+#
+#  Module:  dcmdata
+#
+#  Author:  Andrew Hewett, Marco Eichelberg, Joerg Riesmeier
+#
+#  Purpose:
+#  This is the private tag DICOM data dictionary for the dcmtk class library.
+#
+#
+# Dictionary of Private Tags
+#
+#  This dictionary contains the private tags defined in the following
+#  reference documents (in alphabetical order):
+#   - AGFA IMPAX 6.5.x Solution conformance statement
+#   - Circle Cardiovascular Imaging cmr42 3.0 conformance statement
+#   - David Clunie's dicom3tools package, 2002-04-20 snapshot
+#   - Fuji CR console, 3rd release
+#   - Intelerad Medical Systems Inc., Image Server
+#   - OCULUS Pentacam 1.17 conformance statement
+#   - Philips Digital Diagnost 1.3 conformance statement
+#   - Philips Integris H, catheterization laboratory, RIS-interface
+#   - Philips Intera Achieva conformance statement
+#   - Philips MR Achieva conformance statement
+#   - Siemens Somatom syngo VA40B conformance statement
+#   - Siemens AXIOM Artis VB30 conformance statement
+#   - SonoWand Invite 2.1.1 conformance statement
+#   - Swissvision TR4000 conformance statement
+#   - private tags for DCMTK anonymizer tool
+#
+# Each line represents an entry in the data dictionary.  Each line
+# has 5 fields (Tag, VR, Name, VM, Version).  Entries need not be
+# in ascending tag order.
+#
+# Entries may override existing entries.
+#
+# Each field must be separated by a single tab.
+# The tag value may take one of two forms:
+#   (gggg,"CREATOR",ee)
+#   (gggg,"CREATOR",eeee) [eeee >= 1000]
+# The first form describes a private tag that may be used with different
+# element numbers as reserved by the private creator element.
+# The second form describes a private tag that may only occur with a
+# certain fixed element number.
+# In both cases, the tag values must be in hexadecimal.
+# Repeating groups are represented by indicating the range
+# (gggg-o-gggg,"CREATOR",ee) or (gggg-o-gggg,"CREATOR",eeee)
+# where "-o-" indicates that only odd group numbers match the definition.
+# The element part of the tag can also be a range.
+#
+# Comments have a '#' at the beginning of the line.
+#
+# Tag				VR	Name			VM	Version / Description
+#
+(0019,"1.2.840.113681",10)	ST	CRImageParamsCommon	1	PrivateTag
+(0019,"1.2.840.113681",11)	ST	CRImageIPParamsSingle	1	PrivateTag
+(0019,"1.2.840.113681",12)	ST	CRImageIPParamsLeft	1	PrivateTag
+(0019,"1.2.840.113681",13)	ST	CRImageIPParamsRight	1	PrivateTag
+
+(0087,"1.2.840.113708.794.1.1.2.0",10)	CS	MediaType	1	PrivateTag
+(0087,"1.2.840.113708.794.1.1.2.0",20)	CS	MediaLocation	1	PrivateTag
+(0087,"1.2.840.113708.794.1.1.2.0",50)	IS	EstimatedRetrieveTime	1	PrivateTag
+
+(0009,"ACUSON",00)	IS	Unknown	1	PrivateTag
+(0009,"ACUSON",01)	IS	Unknown	1	PrivateTag
+(0009,"ACUSON",02)	UN	Unknown	1	PrivateTag
+(0009,"ACUSON",03)	UN	Unknown	1	PrivateTag
+(0009,"ACUSON",04)	UN	Unknown	1	PrivateTag
+(0009,"ACUSON",05)	UN	Unknown	1	PrivateTag
+(0009,"ACUSON",06)	UN	Unknown	1	PrivateTag
+(0009,"ACUSON",07)	UN	Unknown	1	PrivateTag
+(0009,"ACUSON",08)	LT	Unknown	1	PrivateTag
+(0009,"ACUSON",09)	LT	Unknown	1	PrivateTag
+(0009,"ACUSON",0a)	IS	Unknown	1	PrivateTag
+(0009,"ACUSON",0b)	IS	Unknown	1	PrivateTag
+(0009,"ACUSON",0c)	IS	Unknown	1	PrivateTag
+(0009,"ACUSON",0d)	IS	Unknown	1	PrivateTag
+(0009,"ACUSON",0e)	IS	Unknown	1	PrivateTag
+(0009,"ACUSON",0f)	UN	Unknown	1	PrivateTag
+(0009,"ACUSON",10)	IS	Unknown	1	PrivateTag
+(0009,"ACUSON",11)	UN	Unknown	1	PrivateTag
+(0009,"ACUSON",12)	IS	Unknown	1	PrivateTag
+(0009,"ACUSON",13)	IS	Unknown	1	PrivateTag
+(0009,"ACUSON",14)	LT	Unknown	1	PrivateTag
+(0009,"ACUSON",15)	UN	Unknown	1	PrivateTag
+
+(0003,"AEGIS_DICOM_2.00",00)	US	Unknown	1-n	PrivateTag
+(0005,"AEGIS_DICOM_2.00",00)	US	Unknown	1-n	PrivateTag
+(0009,"AEGIS_DICOM_2.00",00)	US	Unknown	1-n	PrivateTag
+(0019,"AEGIS_DICOM_2.00",00)	US	Unknown	1-n	PrivateTag
+(0029,"AEGIS_DICOM_2.00",00)	US	Unknown	1-n	PrivateTag
+(1369,"AEGIS_DICOM_2.00",00)	US	Unknown	1-n	PrivateTag
+
+(0009,"AGFA",10)	LO	Unknown	1	PrivateTag
+(0009,"AGFA",11)	LO	Unknown	1	PrivateTag
+(0009,"AGFA",13)	LO	Unknown	1	PrivateTag
+(0009,"AGFA",14)	LO	Unknown	1	PrivateTag
+(0009,"AGFA",15)	LO	Unknown	1	PrivateTag
+
+(0031,"AGFA PACS Archive Mirroring 1.0",00)	CS	StudyStatus	1	PrivateTag
+(0031,"AGFA PACS Archive Mirroring 1.0",01)	UL	DateTimeVerified	1	PrivateTag
+
+(0029,"CAMTRONICS IP",10)	LT	Unknown	1	PrivateTag
+(0029,"CAMTRONICS IP",20)	UN	Unknown	1	PrivateTag
+(0029,"CAMTRONICS IP",30)	UN	Unknown	1	PrivateTag
+(0029,"CAMTRONICS IP",40)	UN	Unknown	1	PrivateTag
+
+(0029,"CAMTRONICS",10)	LT	Commentline	1	PrivateTag
+(0029,"CAMTRONICS",20)	DS	EdgeEnhancementCoefficient	1	PrivateTag
+(0029,"CAMTRONICS",50)	LT	SceneText	1	PrivateTag
+(0029,"CAMTRONICS",60)	LT	ImageText	1	PrivateTag
+(0029,"CAMTRONICS",70)	IS	PixelShiftHorizontal	1	PrivateTag
+(0029,"CAMTRONICS",80)	IS	PixelShiftVertical	1	PrivateTag
+(0029,"CAMTRONICS",90)	IS	Unknown	1	PrivateTag
+
+(0009,"CARDIO-D.R. 1.0",00)	UL	FileLocation	1	PrivateTag
+(0009,"CARDIO-D.R. 1.0",01)	UL	FileSize	1	PrivateTag
+(0009,"CARDIO-D.R. 1.0",40)	SQ	AlternateImageSequence	1	PrivateTag
+(0019,"CARDIO-D.R. 1.0",00)	CS	ImageBlankingShape	1	PrivateTag
+(0019,"CARDIO-D.R. 1.0",02)	IS	ImageBlankingLeftVerticalEdge	1	PrivateTag
+(0019,"CARDIO-D.R. 1.0",04)	IS	ImageBlankingRightVerticalEdge	1	PrivateTag
+(0019,"CARDIO-D.R. 1.0",06)	IS	ImageBlankingUpperHorizontalEdge	1	PrivateTag
+(0019,"CARDIO-D.R. 1.0",08)	IS	ImageBlankingLowerHorizontalEdge	1	PrivateTag
+(0019,"CARDIO-D.R. 1.0",10)	IS	CenterOfCircularImageBlanking	1	PrivateTag
+(0019,"CARDIO-D.R. 1.0",12)	IS	RadiusOfCircularImageBlanking	1	PrivateTag
+(0019,"CARDIO-D.R. 1.0",30)	UL	MaximumImageFrameSize	1	PrivateTag
+(0021,"CARDIO-D.R. 1.0",13)	IS	ImageSequenceNumber	1	PrivateTag
+(0029,"CARDIO-D.R. 1.0",00)	SQ	EdgeEnhancementSequence	1	PrivateTag
+(0029,"CARDIO-D.R. 1.0",01)	US	ConvolutionKernelSize	2	PrivateTag
+(0029,"CARDIO-D.R. 1.0",02)	DS	ConvolutionKernelCoefficients	1-n	PrivateTag
+(0029,"CARDIO-D.R. 1.0",03)	DS	EdgeEnhancementGain	1	PrivateTag
+
+(0025,"CMR42 CIRCLECVI",1010)	LO	WorkspaceID	1	PrivateTag
+(0025,"CMR42 CIRCLECVI",1020)	LO	WorkspaceTimeString	1	PrivateTag
+(0025,"CMR42 CIRCLECVI",1030)	OB	WorkspaceStream	1	PrivateTag
+
+(0009,"DCMTK_ANONYMIZER",00)	SQ	AnonymizerUIDMap	1	PrivateTag
+(0009,"DCMTK_ANONYMIZER",10)	UI	AnonymizerUIDKey	1	PrivateTag
+(0009,"DCMTK_ANONYMIZER",20)	UI	AnonymizerUIDValue	1	PrivateTag
+(0009,"DCMTK_ANONYMIZER",30)	SQ	AnonymizerPatientIDMap	1	PrivateTag
+(0009,"DCMTK_ANONYMIZER",40)	LO	AnonymizerPatientIDKey	1	PrivateTag
+(0009,"DCMTK_ANONYMIZER",50)	LO	AnonymizerPatientIDValue	1	PrivateTag
+
+(0019,"DIDI TO PCR 1.1",22)	UN	RouteAET	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",23)	DS	PCRPrintScale	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",24)	UN	PCRPrintJobEnd	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",25)	IS	PCRNoFilmCopies	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",26)	IS	PCRFilmLayoutPosition	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",27)	UN	PCRPrintReportName	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",70)	UN	RADProtocolPrinter	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",71)	UN	RADProtocolMedium	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",90)	LO	UnprocessedFlag	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",91)	UN	KeyValues	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",92)	UN	DestinationPostprocessingFunction	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",A0)	UN	Version	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",A1)	UN	RangingMode	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",A2)	UN	AbdomenBrightness	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",A3)	UN	FixedBrightness	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",A4)	UN	DetailContrast	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",A5)	UN	ContrastBalance	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",A6)	UN	StructureBoost	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",A7)	UN	StructurePreference	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",A8)	UN	NoiseRobustness	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",A9)	UN	NoiseDoseLimit	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",AA)	UN	NoiseDoseStep	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",AB)	UN	NoiseFrequencyLimit	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",AC)	UN	WeakContrastLimit	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",AD)	UN	StrongContrastLimit	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",AE)	UN	StructureBoostOffset	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",AF)	UN	SmoothGain	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",B0)	UN	MeasureField1	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",B1)	UN	MeasureField2	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",B2)	UN	KeyPercentile1	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",B3)	UN	KeyPercentile2	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",B4)	UN	DensityLUT	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",B5)	UN	Brightness	1	PrivateTag
+(0019,"DIDI TO PCR 1.1",B6)	UN	Gamma	1	PrivateTag
+(0089,"DIDI TO PCR 1.1",10)	SQ	Unknown	1	PrivateTag
+
+(0029,"DIGISCAN IMAGE",31)	US	Unknown	1-n	PrivateTag
+(0029,"DIGISCAN IMAGE",32)	US	Unknown	1-n	PrivateTag
+(0029,"DIGISCAN IMAGE",33)	LT	Unknown	1	PrivateTag
+(0029,"DIGISCAN IMAGE",34)	LT	Unknown	1	PrivateTag
+
+(7001-o-70ff,"DLX_ANNOT_01",04)	ST	TextAnnotation	1	PrivateTag
+(7001-o-70ff,"DLX_ANNOT_01",05)	IS	Box	2	PrivateTag
+(7001-o-70ff,"DLX_ANNOT_01",07)	IS	ArrowEnd	2	PrivateTag
+
+(0015,"DLX_EXAMS_01",01)	DS	StenosisCalibrationRatio	1	PrivateTag
+(0015,"DLX_EXAMS_01",02)	DS	StenosisMagnification	1	PrivateTag
+(0015,"DLX_EXAMS_01",03)	DS	CardiacCalibrationRatio	1	PrivateTag
+
+(6001-o-60ff,"DLX_LKUP_01",01)	US	GrayPaletteColorLookupTableDescriptor	3	PrivateTag
+(6001-o-60ff,"DLX_LKUP_01",02)	US	GrayPaletteColorLookupTableData	1	PrivateTag
+
+(0011,"DLX_PATNT_01",01)	LT	PatientDOB	1	PrivateTag
+
+(0019,"DLX_SERIE_01",01)	DS	AngleValueLArm	1	PrivateTag
+(0019,"DLX_SERIE_01",02)	DS	AngleValuePArm	1	PrivateTag
+(0019,"DLX_SERIE_01",03)	DS	AngleValueCArm	1	PrivateTag
+(0019,"DLX_SERIE_01",04)	CS	AngleLabelLArm	1	PrivateTag
+(0019,"DLX_SERIE_01",05)	CS	AngleLabelPArm	1	PrivateTag
+(0019,"DLX_SERIE_01",06)	CS	AngleLabelCArm	1	PrivateTag
+(0019,"DLX_SERIE_01",07)	ST	ProcedureName	1	PrivateTag
+(0019,"DLX_SERIE_01",08)	ST	ExamName	1	PrivateTag
+(0019,"DLX_SERIE_01",09)	SH	PatientSize	1	PrivateTag
+(0019,"DLX_SERIE_01",0a)	IS	RecordView	1	PrivateTag
+(0019,"DLX_SERIE_01",10)	DS	InjectorDelay	1	PrivateTag
+(0019,"DLX_SERIE_01",11)	CS	AutoInject	1	PrivateTag
+(0019,"DLX_SERIE_01",14)	IS	AcquisitionMode	1	PrivateTag
+(0019,"DLX_SERIE_01",15)	CS	CameraRotationEnabled	1	PrivateTag
+(0019,"DLX_SERIE_01",16)	CS	ReverseSweep	1	PrivateTag
+(0019,"DLX_SERIE_01",17)	IS	SpatialFilterStrength	1	PrivateTag
+(0019,"DLX_SERIE_01",18)	IS	ZoomFactor	1	PrivateTag
+(0019,"DLX_SERIE_01",19)	IS	XZoomCenter	1	PrivateTag
+(0019,"DLX_SERIE_01",1a)	IS	YZoomCenter	1	PrivateTag
+(0019,"DLX_SERIE_01",1b)	DS	Focus	1	PrivateTag
+(0019,"DLX_SERIE_01",1c)	CS	Dose	1	PrivateTag
+(0019,"DLX_SERIE_01",1d)	IS	SideMark	1	PrivateTag
+(0019,"DLX_SERIE_01",1e)	IS	PercentageLandscape	1	PrivateTag
+(0019,"DLX_SERIE_01",1f)	DS	ExposureDuration	1	PrivateTag
+
+(00E1,"ELSCINT1",01)	US	DataDictionaryVersion	1	PrivateTag
+(00E1,"ELSCINT1",14)	LT	Unknown	1	PrivateTag
+(00E1,"ELSCINT1",22)	DS	Unknown	2	PrivateTag
+(00E1,"ELSCINT1",23)	DS	Unknown	2	PrivateTag
+(00E1,"ELSCINT1",24)	LT	Unknown	1	PrivateTag
+(00E1,"ELSCINT1",25)	LT	Unknown	1	PrivateTag
+(00E1,"ELSCINT1",40)	SH	OffsetFromCTMRImages	1	PrivateTag
+(0601,"ELSCINT1",00)	SH	ImplementationVersion	1	PrivateTag
+(0601,"ELSCINT1",20)	DS	RelativeTablePosition	1	PrivateTag
+(0601,"ELSCINT1",21)	DS	RelativeTableHeight	1	PrivateTag
+(0601,"ELSCINT1",30)	SH	SurviewDirection	1	PrivateTag
+(0601,"ELSCINT1",31)	DS	SurviewLength	1	PrivateTag
+(0601,"ELSCINT1",50)	SH	ImageViewType	1	PrivateTag
+(0601,"ELSCINT1",70)	DS	BatchNumber	1	PrivateTag
+(0601,"ELSCINT1",71)	DS	BatchSize	1	PrivateTag
+(0601,"ELSCINT1",72)	DS	BatchSliceNumber	1	PrivateTag
+
+(0009,"FDMS 1.0",04)	SH	ImageControlUnit	1	PrivateTag
+(0009,"FDMS 1.0",05)	OW	ImageUID	1	PrivateTag
+(0009,"FDMS 1.0",06)	OW	RouteImageUID	1	PrivateTag
+(0009,"FDMS 1.0",08)	UL	ImageDisplayInformationVersionNo	1	PrivateTag
+(0009,"FDMS 1.0",09)	UL	PatientInformationVersionNo	1	PrivateTag
+(0009,"FDMS 1.0",0C)	OW	FilmUID	1	PrivateTag
+(0009,"FDMS 1.0",10)	CS	ExposureUnitTypeCode	1	PrivateTag
+(0009,"FDMS 1.0",80)	LO	KanjiHospitalName	1	PrivateTag
+(0009,"FDMS 1.0",90)	ST	DistributionCode	1	PrivateTag
+(0009,"FDMS 1.0",92)	SH	KanjiDepartmentName	1	PrivateTag
+(0009,"FDMS 1.0",F0)	CS	BlackeningProcessFlag	1	PrivateTag
+(0019,"FDMS 1.0",15)	LO	KanjiBodyPartForExposure	1	PrivateTag
+(0019,"FDMS 1.0",32)	LO	KanjiMenuName	1	PrivateTag
+(0019,"FDMS 1.0",40)	CS	ImageProcessingType	1	PrivateTag
+(0019,"FDMS 1.0",50)	CS	EDRMode	1	PrivateTag
+(0019,"FDMS 1.0",60)	SH	RadiographersCode	1	PrivateTag
+(0019,"FDMS 1.0",70)	IS	SplitExposureFormat	1	PrivateTag
+(0019,"FDMS 1.0",71)	IS	NoOfSplitExposureFrames	1	PrivateTag
+(0019,"FDMS 1.0",80)	IS	ReadingPositionSpecification	1	PrivateTag
+(0019,"FDMS 1.0",81)	IS	ReadingSensitivityCenter	1	PrivateTag
+(0019,"FDMS 1.0",90)	SH	FilmAnnotationCharacterString1	1	PrivateTag
+(0019,"FDMS 1.0",91)	SH	FilmAnnotationCharacterString2	1	PrivateTag
+(0021,"FDMS 1.0",10)	CS	FCRImageID	1	PrivateTag
+(0021,"FDMS 1.0",30)	CS	SetNo	1	PrivateTag
+(0021,"FDMS 1.0",40)	IS	ImageNoInTheSet	1	PrivateTag
+(0021,"FDMS 1.0",50)	CS	PairProcessingInformation	1	PrivateTag
+(0021,"FDMS 1.0",80)	OB	EquipmentTypeSpecificInformation	1	PrivateTag
+(0023,"FDMS 1.0",10)	SQ	Unknown	1	PrivateTag
+(0023,"FDMS 1.0",20)	SQ	Unknown	1	PrivateTag
+(0023,"FDMS 1.0",30)	SQ	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",10)	US	RelativeLightEmissionAmountSk	1	PrivateTag
+(0025,"FDMS 1.0",11)	US	TermOfCorrectionForEachIPTypeSt	1	PrivateTag
+(0025,"FDMS 1.0",12)	US	ReadingGainGp	1	PrivateTag
+(0025,"FDMS 1.0",13)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",15)	CS	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",20)	US	Unknown	2	PrivateTag
+(0025,"FDMS 1.0",21)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",30)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",31)	SS	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",32)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",33)	SS	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",34)	SS	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",40)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",41)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",42)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",43)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",50)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",51)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",52)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",53)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",60)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",61)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",62)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",63)	CS	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",70)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",71)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",72)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",73)	US	Unknown	1-n	PrivateTag
+(0025,"FDMS 1.0",74)	US	Unknown	1-n	PrivateTag
+(0025,"FDMS 1.0",80)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",81)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",82)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",83)	US	Unknown	1-n	PrivateTag
+(0025,"FDMS 1.0",84)	US	Unknown	1-n	PrivateTag
+(0025,"FDMS 1.0",90)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",91)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",92)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",93)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",94)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",95)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",96)	CS	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",a0)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",a1)	SS	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",a2)	US	Unknown	1	PrivateTag
+(0025,"FDMS 1.0",a3)	SS	Unknown	1	PrivateTag
+(0027,"FDMS 1.0",10)	SQ	Unknown	1	PrivateTag
+(0027,"FDMS 1.0",20)	SQ	Unknown	1	PrivateTag
+(0027,"FDMS 1.0",30)	SQ	Unknown	1	PrivateTag
+(0027,"FDMS 1.0",40)	SQ	Unknown	1	PrivateTag
+(0027,"FDMS 1.0",50)	SQ	Unknown	1	PrivateTag
+(0027,"FDMS 1.0",60)	SQ	Unknown	1	PrivateTag
+(0027,"FDMS 1.0",70)	SQ	Unknown	1	PrivateTag
+(0027,"FDMS 1.0",80)	SQ	Unknown	1	PrivateTag
+(0027,"FDMS 1.0",a0)	IS	Unknown	1	PrivateTag
+(0027,"FDMS 1.0",a1)	CS	Unknown	2	PrivateTag
+(0027,"FDMS 1.0",a2)	CS	Unknown	2	PrivateTag
+(0027,"FDMS 1.0",a3)	SS	Unknown	1-n	PrivateTag
+(0029,"FDMS 1.0",20)	CS	ImageScanningDirection	1	PrivateTag
+(0029,"FDMS 1.0",30)	CS	ExtendedReadingSizeValue	1	PrivateTag
+(0029,"FDMS 1.0",34)	US	MagnificationReductionRatio	1	PrivateTag
+(0029,"FDMS 1.0",44)	CS	LineDensityCode	1	PrivateTag
+(0029,"FDMS 1.0",50)	CS	DataCompressionCode	1	PrivateTag
+(2011,"FDMS 1.0",11)	CS	ImagePosition SpecifyingFlag	1	PrivateTag
+(50F1,"FDMS 1.0",06)	CS	EnergySubtractionParam	1	PrivateTag
+(50F1,"FDMS 1.0",07)	CS	SubtractionRegistrationResult	1	PrivateTag
+(50F1,"FDMS 1.0",08)	CS	EnergySubtractionParam2	1	PrivateTag
+(50F1,"FDMS 1.0",09)	SL	AfinConversionCoefficient	1	PrivateTag
+(50F1,"FDMS 1.0",10)	CS	FilmOutputFormat	1	PrivateTag
+(50F1,"FDMS 1.0",20)	CS	ImageProcessingModificationFlag	1	PrivateTag
+
+(0009,"FFP DATA",01)	UN	CRHeaderInformation	1	PrivateTag
+
+(0019,"GE ??? From Adantage Review CS",30)	LO	CREDRMode	1	PrivateTag
+(0019,"GE ??? From Adantage Review CS",40)	LO	CRLatitude	1	PrivateTag
+(0019,"GE ??? From Adantage Review CS",50)	LO	CRGroupNumber	1	PrivateTag
+(0019,"GE ??? From Adantage Review CS",70)	LO	CRImageSerialNumber	1	PrivateTag
+(0019,"GE ??? From Adantage Review CS",80)	LO	CRBarCodeNumber	1	PrivateTag
+(0019,"GE ??? From Adantage Review CS",90)	LO	CRFilmOutputExposures	1	PrivateTag
+
+(0009,"GEMS_ACQU_01",24)	DS	Unknown	1	PrivateTag
+(0009,"GEMS_ACQU_01",25)	US	Unknown	1	PrivateTag
+(0009,"GEMS_ACQU_01",3e)	US	Unknown	1	PrivateTag
+(0009,"GEMS_ACQU_01",3f)	US	Unknown	1	PrivateTag
+(0009,"GEMS_ACQU_01",42)	US	Unknown	1	PrivateTag
+(0009,"GEMS_ACQU_01",43)	US	Unknown	1	PrivateTag
+(0009,"GEMS_ACQU_01",f8)	US	Unknown	1	PrivateTag
+(0009,"GEMS_ACQU_01",fb)	IS	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",01)	LT	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",02)	SL	NumberOfCellsInDetector	1	PrivateTag
+(0019,"GEMS_ACQU_01",03)	DS	CellNumberAtTheta	1	PrivateTag
+(0019,"GEMS_ACQU_01",04)	DS	CellSpacing	1	PrivateTag
+(0019,"GEMS_ACQU_01",05)	LT	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",06)	UN	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",0e)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",0f)	DS	HorizontalFrameOfReference	1	PrivateTag
+(0019,"GEMS_ACQU_01",11)	SS	SeriesContrast	1	PrivateTag
+(0019,"GEMS_ACQU_01",12)	SS	LastPseq	1	PrivateTag
+(0019,"GEMS_ACQU_01",13)	SS	StartNumberForBaseline	1	PrivateTag
+(0019,"GEMS_ACQU_01",14)	SS	End NumberForBaseline	1	PrivateTag
+(0019,"GEMS_ACQU_01",15)	SS	StartNumberForEnhancedScans	1	PrivateTag
+(0019,"GEMS_ACQU_01",16)	SS	EndNumberForEnhancedScans	1	PrivateTag
+(0019,"GEMS_ACQU_01",17)	SS	SeriesPlane	1	PrivateTag
+(0019,"GEMS_ACQU_01",18)	LO	FirstScanRAS	1	PrivateTag
+(0019,"GEMS_ACQU_01",19)	DS	FirstScanLocation	1	PrivateTag
+(0019,"GEMS_ACQU_01",1a)	LO	LastScanRAS	1	PrivateTag
+(0019,"GEMS_ACQU_01",1b)	DS	LastScanLocation	1	PrivateTag
+(0019,"GEMS_ACQU_01",1e)	DS	DisplayFieldOfView	1	PrivateTag
+(0019,"GEMS_ACQU_01",20)	DS	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",22)	DS	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",23)	DS	TableSpeed	1	PrivateTag
+(0019,"GEMS_ACQU_01",24)	DS	MidScanTime	1	PrivateTag
+(0019,"GEMS_ACQU_01",25)	SS	MidScanFlag	1	PrivateTag
+(0019,"GEMS_ACQU_01",26)	SL	DegreesOfAzimuth	1	PrivateTag
+(0019,"GEMS_ACQU_01",27)	DS	GantryPeriod	1	PrivateTag
+(0019,"GEMS_ACQU_01",2a)	DS	XrayOnPosition	1	PrivateTag
+(0019,"GEMS_ACQU_01",2b)	DS	XrayOffPosition	1	PrivateTag
+(0019,"GEMS_ACQU_01",2c)	SL	NumberOfTriggers	1	PrivateTag
+(0019,"GEMS_ACQU_01",2d)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",2e)	DS	AngleOfFirstView	1	PrivateTag
+(0019,"GEMS_ACQU_01",2f)	DS	TriggerFrequency	1	PrivateTag
+(0019,"GEMS_ACQU_01",39)	SS	ScanFOVType	1	PrivateTag
+(0019,"GEMS_ACQU_01",3a)	IS	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",3b)	LT	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",3c)	UN	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",3e)	UN	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",3f)	UN	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",40)	SS	StatReconFlag	1	PrivateTag
+(0019,"GEMS_ACQU_01",41)	SS	ComputeType	1	PrivateTag
+(0019,"GEMS_ACQU_01",42)	SS	SegmentNumber	1	PrivateTag
+(0019,"GEMS_ACQU_01",43)	SS	TotalSegmentsRequested	1	PrivateTag
+(0019,"GEMS_ACQU_01",44)	DS	InterscanDelay	1	PrivateTag
+(0019,"GEMS_ACQU_01",47)	SS	ViewCompressionFactor	1	PrivateTag
+(0019,"GEMS_ACQU_01",48)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",49)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",4a)	SS	TotalNumberOfRefChannels	1	PrivateTag
+(0019,"GEMS_ACQU_01",4b)	SL	DataSizeForScanData	1	PrivateTag
+(0019,"GEMS_ACQU_01",52)	SS	ReconPostProcessingFlag	1	PrivateTag
+(0019,"GEMS_ACQU_01",54)	UN	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",57)	SS	CTWaterNumber	1	PrivateTag
+(0019,"GEMS_ACQU_01",58)	SS	CTBoneNumber	1	PrivateTag
+(0019,"GEMS_ACQU_01",5a)	FL	AcquisitionDuration	1	PrivateTag
+(0019,"GEMS_ACQU_01",5d)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",5e)	SL	NumberOfChannels1To512	1	PrivateTag
+(0019,"GEMS_ACQU_01",5f)	SL	IncrementBetweenChannels	1	PrivateTag
+(0019,"GEMS_ACQU_01",60)	SL	StartingView	1	PrivateTag
+(0019,"GEMS_ACQU_01",61)	SL	NumberOfViews	1	PrivateTag
+(0019,"GEMS_ACQU_01",62)	SL	IncrementBetweenViews	1	PrivateTag
+(0019,"GEMS_ACQU_01",6a)	SS	DependantOnNumberOfViewsProcessed	1	PrivateTag
+(0019,"GEMS_ACQU_01",6b)	SS	FieldOfViewInDetectorCells	1	PrivateTag
+(0019,"GEMS_ACQU_01",70)	SS	ValueOfBackProjectionButton	1	PrivateTag
+(0019,"GEMS_ACQU_01",71)	SS	SetIfFatqEstimatesWereUsed	1	PrivateTag
+(0019,"GEMS_ACQU_01",72)	DS	ZChannelAvgOverViews	1	PrivateTag
+(0019,"GEMS_ACQU_01",73)	DS	AvgOfLeftRefChannelsOverViews	1	PrivateTag
+(0019,"GEMS_ACQU_01",74)	DS	MaxLeftChannelOverViews	1	PrivateTag
+(0019,"GEMS_ACQU_01",75)	DS	AvgOfRightRefChannelsOverViews	1	PrivateTag
+(0019,"GEMS_ACQU_01",76)	DS	MaxRightChannelOverViews	1	PrivateTag
+(0019,"GEMS_ACQU_01",7d)	DS	SecondEcho	1	PrivateTag
+(0019,"GEMS_ACQU_01",7e)	SS	NumberOfEchos	1	PrivateTag
+(0019,"GEMS_ACQU_01",7f)	DS	TableDelta	1	PrivateTag
+(0019,"GEMS_ACQU_01",81)	SS	Contiguous	1	PrivateTag
+(0019,"GEMS_ACQU_01",82)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",83)	DS	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",84)	DS	PeakSAR	1	PrivateTag
+(0019,"GEMS_ACQU_01",85)	SS	MonitorSAR	1	PrivateTag
+(0019,"GEMS_ACQU_01",86)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",87)	DS	CardiacRepetition Time	1	PrivateTag
+(0019,"GEMS_ACQU_01",88)	SS	ImagesPerCardiacCycle	1	PrivateTag
+(0019,"GEMS_ACQU_01",8a)	SS	ActualReceiveGainAnalog	1	PrivateTag
+(0019,"GEMS_ACQU_01",8b)	SS	ActualReceiveGainDigital	1	PrivateTag
+(0019,"GEMS_ACQU_01",8d)	DS	DelayAfterTrigger	1	PrivateTag
+(0019,"GEMS_ACQU_01",8f)	SS	SwapPhaseFrequency	1	PrivateTag
+(0019,"GEMS_ACQU_01",90)	SS	PauseInterval	1	PrivateTag
+(0019,"GEMS_ACQU_01",91)	DS	PulseTime	1	PrivateTag
+(0019,"GEMS_ACQU_01",92)	SL	SliceOffsetOnFrequencyAxis	1	PrivateTag
+(0019,"GEMS_ACQU_01",93)	DS	CenterFrequency	1	PrivateTag
+(0019,"GEMS_ACQU_01",94)	SS	TransmitGain	1	PrivateTag
+(0019,"GEMS_ACQU_01",95)	SS	AnalogReceiverGain	1	PrivateTag
+(0019,"GEMS_ACQU_01",96)	SS	DigitalReceiverGain	1	PrivateTag
+(0019,"GEMS_ACQU_01",97)	SL	BitmapDefiningCVs	1	PrivateTag
+(0019,"GEMS_ACQU_01",98)	SS	CenterFrequencyMethod	1	PrivateTag
+(0019,"GEMS_ACQU_01",99)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",9b)	SS	PulseSequenceMode	1	PrivateTag
+(0019,"GEMS_ACQU_01",9c)	LO	PulseSequenceName	1	PrivateTag
+(0019,"GEMS_ACQU_01",9d)	DT	PulseSequenceDate	1	PrivateTag
+(0019,"GEMS_ACQU_01",9e)	LO	InternalPulseSequenceName	1	PrivateTag
+(0019,"GEMS_ACQU_01",9f)	SS	TransmittingCoil	1	PrivateTag
+(0019,"GEMS_ACQU_01",a0)	SS	SurfaceCoilType	1	PrivateTag
+(0019,"GEMS_ACQU_01",a1)	SS	ExtremityCoilFlag	1	PrivateTag
+(0019,"GEMS_ACQU_01",a2)	SL	RawDataRunNumber	1	PrivateTag
+(0019,"GEMS_ACQU_01",a3)	UL	CalibratedFieldStrength	1	PrivateTag
+(0019,"GEMS_ACQU_01",a4)	SS	SATFatWaterBone	1	PrivateTag
+(0019,"GEMS_ACQU_01",a5)	DS	ReceiveBandwidth	1	PrivateTag
+(0019,"GEMS_ACQU_01",a7)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",a8)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",a9)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",aa)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",ab)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",ac)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",ad)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",ae)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",af)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",b0)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",b1)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",b2)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",b3)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",b4)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",b5)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",b6)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",b7)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",b8)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",b9)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",ba)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",bb)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",bc)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",bd)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",be)	DS	ProjectionAngle	1	PrivateTag
+(0019,"GEMS_ACQU_01",c0)	SS	SaturationPlanes	1	PrivateTag
+(0019,"GEMS_ACQU_01",c1)	SS	SurfaceCoilIntensityCorrectionFlag	1	PrivateTag
+(0019,"GEMS_ACQU_01",c2)	SS	SATLocationR	1	PrivateTag
+(0019,"GEMS_ACQU_01",c3)	SS	SATLocationL	1	PrivateTag
+(0019,"GEMS_ACQU_01",c4)	SS	SATLocationA	1	PrivateTag
+(0019,"GEMS_ACQU_01",c5)	SS	SATLocationP	1	PrivateTag
+(0019,"GEMS_ACQU_01",c6)	SS	SATLocationH	1	PrivateTag
+(0019,"GEMS_ACQU_01",c7)	SS	SATLocationF	1	PrivateTag
+(0019,"GEMS_ACQU_01",c8)	SS	SATThicknessRL	1	PrivateTag
+(0019,"GEMS_ACQU_01",c9)	SS	SATThicknessAP	1	PrivateTag
+(0019,"GEMS_ACQU_01",ca)	SS	SATThicknessHF	1	PrivateTag
+(0019,"GEMS_ACQU_01",cb)	SS	PrescribedFlowAxis	1	PrivateTag
+(0019,"GEMS_ACQU_01",cc)	SS	VelocityEncoding	1	PrivateTag
+(0019,"GEMS_ACQU_01",cd)	SS	ThicknessDisclaimer	1	PrivateTag
+(0019,"GEMS_ACQU_01",ce)	SS	PrescanType	1	PrivateTag
+(0019,"GEMS_ACQU_01",cf)	SS	PrescanStatus	1	PrivateTag
+(0019,"GEMS_ACQU_01",d0)	SH	RawDataType	1	PrivateTag
+(0019,"GEMS_ACQU_01",d2)	SS	ProjectionAlgorithm	1	PrivateTag
+(0019,"GEMS_ACQU_01",d3)	SH	ProjectionAlgorithm	1	PrivateTag
+(0019,"GEMS_ACQU_01",d4)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",d5)	SS	FractionalEcho	1	PrivateTag
+(0019,"GEMS_ACQU_01",d6)	SS	PrepPulse	1	PrivateTag
+(0019,"GEMS_ACQU_01",d7)	SS	CardiacPhases	1	PrivateTag
+(0019,"GEMS_ACQU_01",d8)	SS	VariableEchoFlag	1	PrivateTag
+(0019,"GEMS_ACQU_01",d9)	DS	ConcatenatedSAT	1	PrivateTag
+(0019,"GEMS_ACQU_01",da)	SS	ReferenceChannelUsed	1	PrivateTag
+(0019,"GEMS_ACQU_01",db)	DS	BackProjectorCoefficient	1	PrivateTag
+(0019,"GEMS_ACQU_01",dc)	SS	PrimarySpeedCorrectionUsed	1	PrivateTag
+(0019,"GEMS_ACQU_01",dd)	SS	OverrangeCorrectionUsed	1	PrivateTag
+(0019,"GEMS_ACQU_01",de)	DS	DynamicZAlphaValue	1	PrivateTag
+(0019,"GEMS_ACQU_01",df)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",e0)	DS	UserData	1	PrivateTag
+(0019,"GEMS_ACQU_01",e1)	DS	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",e2)	DS	VelocityEncodeScale	1	PrivateTag
+(0019,"GEMS_ACQU_01",e3)	LT	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",e4)	LT	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",e5)	IS	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",e6)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",e8)	DS	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",e9)	DS	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",eb)	DS	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",ec)	US	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",f0)	UN	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",f1)	LT	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",f2)	SS	FastPhases	1	PrivateTag
+(0019,"GEMS_ACQU_01",f3)	LT	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",f4)	LT	Unknown	1	PrivateTag
+(0019,"GEMS_ACQU_01",f9)	DS	TransmitGain	1	PrivateTag
+
+(0023,"GEMS_ACRQA_1.0 BLOCK1",00)	LO	CRExposureMenuCode	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",10)	LO	CRExposureMenuString	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",20)	LO	CREDRMode	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",30)	LO	CRLatitude	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",40)	LO	CRGroupNumber	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",50)	US	CRImageSerialNumber	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",60)	LO	CRBarCodeNumber	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",70)	LO	CRFilmOutputExposure	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",80)	LO	CRFilmFormat	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",90)	LO	CRSShiftString	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",00)	US	CRSShift	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",10)	DS	CRCShift	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",20)	DS	CRGT	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",30)	DS	CRGA	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",40)	DS	CRGC	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",50)	DS	CRGS	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",60)	DS	CRRT	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",70)	DS	CRRE	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",80)	US	CRRN	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",90)	DS	CRDRT	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",00)	DS	CRDRE	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",10)	US	CRDRN	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",20)	DS	CRORE	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",30)	US	CRORN	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",40)	US	CRORD	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",50)	LO	CRCassetteSize	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",60)	LO	CRMachineID	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",70)	LO	CRMachineType	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",80)	LO	CRTechnicianCode	1	PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",90)	LO	CREnergySubtractionParameters	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",00)	LO	CRExposureMenuCode	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",10)	LO	CRExposureMenuString	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",20)	LO	CREDRMode	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",30)	LO	CRLatitude	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",40)	LO	CRGroupNumber	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",50)	US	CRImageSerialNumber	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",60)	LO	CRBarCodeNumber	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",70)	LO	CRFilmOutputExposure	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",80)	LO	CRFilmFormat	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",90)	LO	CRSShiftString	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",00)	US	CRSShift	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",10)	LO	CRCShift	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",20)	LO	CRGT	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",30)	DS	CRGA	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",40)	DS	CRGC	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",50)	DS	CRGS	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",60)	LO	CRRT	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",70)	DS	CRRE	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",80)	US	CRRN	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",90)	DS	CRDRT	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",00)	DS	CRDRE	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",10)	US	CRDRN	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",20)	DS	CRORE	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",30)	US	CRORN	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",40)	US	CRORD	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",50)	LO	CRCassetteSize	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",60)	LO	CRMachineID	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",70)	LO	CRMachineType	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",80)	LO	CRTechnicianCode	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",90)	LO	CREnergySubtractionParameters	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",f0)	LO	CRDistributionCode	1	PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",ff)	US	CRShuttersApplied	1	PrivateTag
+
+(0047,"GEMS_ADWSoft_3D1",01)	SQ	Reconstruction Parameters Sequence	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",50)	UL	VolumeVoxelCount	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",51)	UL	VolumeSegmentCount	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",53)	US	VolumeSliceSize	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",54)	US	VolumeSliceCount	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",55)	SL	VolumeThresholdValue	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",57)	DS	VolumeVoxelRatio	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",58)	DS	VolumeVoxelSize	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",59)	US	VolumeZPositionSize	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",60)	DS	VolumeBaseLine	9	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",61)	DS	VolumeCenterPoint	3	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",63)	SL	VolumeSkewBase	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",64)	DS	VolumeRegistrationTransformRotationMatrix	9	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",65)	DS	VolumeRegistrationTransformTranslationVector	3	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",70)	DS	KVPList	1-n	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",71)	IS	XRayTubeCurrentList	1-n	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",72)	IS	ExposureList	1-n	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",80)	LO	AcquisitionDLXIdentifier	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",85)	SQ	AcquisitionDLX2DSeriesSequence	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",89)	DS	ContrastAgentVolumeList	1-n	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",8A)	US	NumberOfInjections	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",8B)	US	FrameCount	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",91)	LO	XA3DReconstructionAlgorithmName	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",92)	CS	XA3DReconstructionAlgorithmVersion	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",93)	DA	DLXCalibrationDate	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",94)	TM	DLXCalibrationTime	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",95)	CS	DLXCalibrationStatus	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",96)	IS	UsedFrames	1-n	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",98)	US	TransformCount	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",99)	SQ	TransformSequence	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",9A)	DS	TransformRotationMatrix	9	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",9B)	DS	TransformTranslationVector	3	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",9C)	LO	TransformLabel	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B0)	SQ	WireframeList	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B1)	US	WireframeCount	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B2)	US	LocationSystem	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B5)	LO	WireframeName	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B6)	LO	WireframeGroupName	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B7)	LO	WireframeColor	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B8)	SL	WireframeAttributes	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B9)	SL	WireframePointCount	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",BA)	SL	WireframeTimestamp	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",BB)	SQ	WireframePointList	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",BC)	DS	WireframePointsCoordinates	3	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",C0)	DS	VolumeUpperLeftHighCornerRAS	3	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",C1)	DS	VolumeSliceToRASRotationMatrix	9	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",C2)	DS	VolumeUpperLeftHighCornerTLOC	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",D1)	OB	VolumeSegmentList	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",D2)	OB	VolumeGradientList	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",D3)	OB	VolumeDensityList	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",D4)	OB	VolumeZPositionList	1	PrivateTag
+(0047,"GEMS_ADWSoft_3D1",D5)	OB	VolumeOriginalIndexList	1	PrivateTag
+(0039,"GEMS_ADWSoft_DPO",80)	IS	PrivateEntityNumber	1	PrivateTag
+(0039,"GEMS_ADWSoft_DPO",85)	DA	PrivateEntityDate	1	PrivateTag
+(0039,"GEMS_ADWSoft_DPO",90)	TM	PrivateEntityTime	1	PrivateTag
+(0039,"GEMS_ADWSoft_DPO",95)	LO	PrivateEntityLaunchCommand	1	PrivateTag
+(0039,"GEMS_ADWSoft_DPO",AA)	CS	PrivateEntityType	1	PrivateTag
+
+(0033,"GEMS_CTHD_01",02)	UN	Unknown	1	PrivateTag
+
+(0037,"GEMS_DRS_1",10)	LO	ReferringDepartment	1	PrivateTag
+(0037,"GEMS_DRS_1",20)	US	ScreenNumber	1	PrivateTag
+(0037,"GEMS_DRS_1",40)	SH	LeftOrientation	1	PrivateTag
+(0037,"GEMS_DRS_1",42)	SH	RightOrientation	1	PrivateTag
+(0037,"GEMS_DRS_1",50)	CS	Inversion	1	PrivateTag
+(0037,"GEMS_DRS_1",60)	US	DSA	1	PrivateTag
+
+(0009,"GEMS_GENIE_1",10)	LO	Unknown	1	PrivateTag
+(0009,"GEMS_GENIE_1",11)	SL	StudyFlags	1	PrivateTag
+(0009,"GEMS_GENIE_1",12)	SL	StudyType	1	PrivateTag
+(0009,"GEMS_GENIE_1",1e)	UI	Unknown	1	PrivateTag
+(0009,"GEMS_GENIE_1",20)	LO	Unknown	1	PrivateTag
+(0009,"GEMS_GENIE_1",21)	SL	SeriesFlags	1	PrivateTag
+(0009,"GEMS_GENIE_1",22)	SH	UserOrientation	1	PrivateTag
+(0009,"GEMS_GENIE_1",23)	SL	InitiationType	1	PrivateTag
+(0009,"GEMS_GENIE_1",24)	SL	InitiationDelay	1	PrivateTag
+(0009,"GEMS_GENIE_1",25)	SL	InitiationCountRate	1	PrivateTag
+(0009,"GEMS_GENIE_1",26)	SL	NumberEnergySets	1	PrivateTag
+(0009,"GEMS_GENIE_1",27)	SL	NumberDetectors	1	PrivateTag
+(0009,"GEMS_GENIE_1",29)	SL	Unknown	1	PrivateTag
+(0009,"GEMS_GENIE_1",2a)	SL	Unknown	1	PrivateTag
+(0009,"GEMS_GENIE_1",2c)	LO	SeriesComments	1	PrivateTag
+(0009,"GEMS_GENIE_1",2d)	SL	TrackBeatAverage	1	PrivateTag
+(0009,"GEMS_GENIE_1",2e)	FD	DistancePrescribed	1	PrivateTag
+(0009,"GEMS_GENIE_1",30)	LO	Unknown	1	PrivateTag
+(0009,"GEMS_GENIE_1",35)	SL	GantryLocusType	1	PrivateTag
+(0009,"GEMS_GENIE_1",37)	SL	StartingHeartRate	1	PrivateTag
+(0009,"GEMS_GENIE_1",38)	SL	RRWindowWidth	1	PrivateTag
+(0009,"GEMS_GENIE_1",39)	SL	RRWindowOffset	1	PrivateTag
+(0009,"GEMS_GENIE_1",3a)	SL	PercentCycleImaged	1	PrivateTag
+(0009,"GEMS_GENIE_1",40)	LO	Unknown	1	PrivateTag
+(0009,"GEMS_GENIE_1",41)	SL	PatientFlags	1	PrivateTag
+(0009,"GEMS_GENIE_1",42)	DA	PatientCreationDate	1	PrivateTag
+(0009,"GEMS_GENIE_1",43)	TM	PatientCreationTime	1	PrivateTag
+(0011,"GEMS_GENIE_1",0a)	SL	SeriesType	1	PrivateTag
+(0011,"GEMS_GENIE_1",0b)	SL	EffectiveSeriesDuration	1	PrivateTag
+(0011,"GEMS_GENIE_1",0c)	SL	NumBeats	1	PrivateTag
+(0011,"GEMS_GENIE_1",0d)	LO	RadioNuclideName	1	PrivateTag
+(0011,"GEMS_GENIE_1",10)	LO	Unknown	1	PrivateTag
+(0011,"GEMS_GENIE_1",12)	LO	DatasetName	1	PrivateTag
+(0011,"GEMS_GENIE_1",13)	SL	DatasetType	1	PrivateTag
+(0011,"GEMS_GENIE_1",15)	SL	DetectorNumber	1	PrivateTag
+(0011,"GEMS_GENIE_1",16)	SL	EnergyNumber	1	PrivateTag
+(0011,"GEMS_GENIE_1",17)	SL	RRIntervalWindowNumber	1	PrivateTag
+(0011,"GEMS_GENIE_1",18)	SL	MGBinNumber	1	PrivateTag
+(0011,"GEMS_GENIE_1",19)	FD	RadiusOfRotation	1	PrivateTag
+(0011,"GEMS_GENIE_1",1a)	SL	DetectorCountZone	1	PrivateTag
+(0011,"GEMS_GENIE_1",1b)	SL	NumEnergyWindows	1	PrivateTag
+(0011,"GEMS_GENIE_1",1c)	SL	EnergyOffset	4	PrivateTag
+(0011,"GEMS_GENIE_1",1d)	SL	EnergyRange	1	PrivateTag
+(0011,"GEMS_GENIE_1",1f)	SL	ImageOrientation	1	PrivateTag
+(0011,"GEMS_GENIE_1",23)	SL	UseFOVMask	1	PrivateTag
+(0011,"GEMS_GENIE_1",24)	SL	FOVMaskYCutoffAngle	1	PrivateTag
+(0011,"GEMS_GENIE_1",25)	SL	FOVMaskCutoffAngle	1	PrivateTag
+(0011,"GEMS_GENIE_1",26)	SL	TableOrientation	1	PrivateTag
+(0011,"GEMS_GENIE_1",27)	SL	ROITopLeft	2	PrivateTag
+(0011,"GEMS_GENIE_1",28)	SL	ROIBottomRight	2	PrivateTag
+(0011,"GEMS_GENIE_1",30)	LO	Unknown	1	PrivateTag
+(0011,"GEMS_GENIE_1",33)	LO	EnergyCorrectName	1	PrivateTag
+(0011,"GEMS_GENIE_1",34)	LO	SpatialCorrectName	1	PrivateTag
+(0011,"GEMS_GENIE_1",35)	LO	TuningCalibName	1	PrivateTag
+(0011,"GEMS_GENIE_1",36)	LO	UniformityCorrectName	1	PrivateTag
+(0011,"GEMS_GENIE_1",37)	LO	AcquisitionSpecificCorrectName	1	PrivateTag
+(0011,"GEMS_GENIE_1",38)	SL	ByteOrder	1	PrivateTag
+(0011,"GEMS_GENIE_1",3a)	SL	PictureFormat	1	PrivateTag
+(0011,"GEMS_GENIE_1",3b)	FD	PixelScale	1	PrivateTag
+(0011,"GEMS_GENIE_1",3c)	FD	PixelOffset	1	PrivateTag
+(0011,"GEMS_GENIE_1",3e)	SL	FOVShape	1	PrivateTag
+(0011,"GEMS_GENIE_1",3f)	SL	DatasetFlags	1	PrivateTag
+(0011,"GEMS_GENIE_1",44)	FD	ThresholdCenter	1	PrivateTag
+(0011,"GEMS_GENIE_1",45)	FD	ThresholdWidth	1	PrivateTag
+(0011,"GEMS_GENIE_1",46)	SL	InterpolationType	1	PrivateTag
+(0011,"GEMS_GENIE_1",55)	FD	Period	1	PrivateTag
+(0011,"GEMS_GENIE_1",56)	FD	ElapsedTime	1	PrivateTag
+(0013,"GEMS_GENIE_1",10)	FD	DigitalFOV	2	PrivateTag
+(0013,"GEMS_GENIE_1",11)	SL	Unknown	1	PrivateTag
+(0013,"GEMS_GENIE_1",12)	SL	Unknown	1	PrivateTag
+(0013,"GEMS_GENIE_1",16)	SL	AutoTrackPeak	1	PrivateTag
+(0013,"GEMS_GENIE_1",17)	SL	AutoTrackWidth	1	PrivateTag
+(0013,"GEMS_GENIE_1",18)	FD	TransmissionScanTime	1	PrivateTag
+(0013,"GEMS_GENIE_1",19)	FD	TransmissionMaskWidth	1	PrivateTag
+(0013,"GEMS_GENIE_1",1a)	FD	CopperAttenuatorThickness	1	PrivateTag
+(0013,"GEMS_GENIE_1",1c)	FD	Unknown	1	PrivateTag
+(0013,"GEMS_GENIE_1",1d)	FD	Unknown	1	PrivateTag
+(0013,"GEMS_GENIE_1",1e)	FD	TomoViewOffset	1-n	PrivateTag
+(0013,"GEMS_GENIE_1",26)	LT	StudyComments	1	PrivateTag
+
+(0033,"GEMS_GNHD_01",01)	UN	Unknown	1	PrivateTag
+(0033,"GEMS_GNHD_01",02)	UN	Unknown	1	PrivateTag
+
+(0009,"GEMS_IDEN_01",01)	LO	FullFidelity	1	PrivateTag
+(0009,"GEMS_IDEN_01",02)	SH	SuiteId	1	PrivateTag
+(0009,"GEMS_IDEN_01",04)	SH	ProductId	1	PrivateTag
+(0009,"GEMS_IDEN_01",17)	LT	Unknown	1	PrivateTag
+(0009,"GEMS_IDEN_01",1a)	US	Unknown	1	PrivateTag
+(0009,"GEMS_IDEN_01",20)	US	Unknown	1	PrivateTag
+(0009,"GEMS_IDEN_01",27)	SL	ImageActualDate	1	PrivateTag
+(0009,"GEMS_IDEN_01",2f)	LT	Unknown	1	PrivateTag
+(0009,"GEMS_IDEN_01",30)	SH	ServiceId	1	PrivateTag
+(0009,"GEMS_IDEN_01",31)	SH	MobileLocationNumber	1	PrivateTag
+(0009,"GEMS_IDEN_01",e2)	LT	Unknown	1	PrivateTag
+(0009,"GEMS_IDEN_01",e3)	UI	EquipmentUID	1	PrivateTag
+(0009,"GEMS_IDEN_01",e6)	SH	GenesisVersionNow	1	PrivateTag
+(0009,"GEMS_IDEN_01",e7)	UL	ExamRecordChecksum	1	PrivateTag
+(0009,"GEMS_IDEN_01",e8)	UL	Unknown	1	PrivateTag
+(0009,"GEMS_IDEN_01",e9)	SL	ActualSeriesDataTimeStamp	1	PrivateTag
+
+(0027,"GEMS_IMAG_01",06)	SL	ImageArchiveFlag	1	PrivateTag
+(0027,"GEMS_IMAG_01",10)	SS	ScoutType	1	PrivateTag
+(0027,"GEMS_IMAG_01",1c)	SL	VmaMamp	1	PrivateTag
+(0027,"GEMS_IMAG_01",1d)	SS	VmaPhase	1	PrivateTag
+(0027,"GEMS_IMAG_01",1e)	SL	VmaMod	1	PrivateTag
+(0027,"GEMS_IMAG_01",1f)	SL	VmaClip	1	PrivateTag
+(0027,"GEMS_IMAG_01",20)	SS	SmartScanOnOffFlag	1	PrivateTag
+(0027,"GEMS_IMAG_01",30)	SH	ForeignImageRevision	1	PrivateTag
+(0027,"GEMS_IMAG_01",31)	SS	ImagingMode	1	PrivateTag
+(0027,"GEMS_IMAG_01",32)	SS	PulseSequence	1	PrivateTag
+(0027,"GEMS_IMAG_01",33)	SL	ImagingOptions	1	PrivateTag
+(0027,"GEMS_IMAG_01",35)	SS	PlaneType	1	PrivateTag
+(0027,"GEMS_IMAG_01",36)	SL	ObliquePlane	1	PrivateTag
+(0027,"GEMS_IMAG_01",40)	SH	RASLetterOfImageLocation	1	PrivateTag
+(0027,"GEMS_IMAG_01",41)	FL	ImageLocation	1	PrivateTag
+(0027,"GEMS_IMAG_01",42)	FL	CenterRCoordOfPlaneImage	1	PrivateTag
+(0027,"GEMS_IMAG_01",43)	FL	CenterACoordOfPlaneImage	1	PrivateTag
+(0027,"GEMS_IMAG_01",44)	FL	CenterSCoordOfPlaneImage	1	PrivateTag
+(0027,"GEMS_IMAG_01",45)	FL	NormalRCoord	1	PrivateTag
+(0027,"GEMS_IMAG_01",46)	FL	NormalACoord	1	PrivateTag
+(0027,"GEMS_IMAG_01",47)	FL	NormalSCoord	1	PrivateTag
+(0027,"GEMS_IMAG_01",48)	FL	RCoordOfTopRightCorner	1	PrivateTag
+(0027,"GEMS_IMAG_01",49)	FL	ACoordOfTopRightCorner	1	PrivateTag
+(0027,"GEMS_IMAG_01",4a)	FL	SCoordOfTopRightCorner	1	PrivateTag
+(0027,"GEMS_IMAG_01",4b)	FL	RCoordOfBottomRightCorner	1	PrivateTag
+(0027,"GEMS_IMAG_01",4c)	FL	ACoordOfBottomRightCorner	1	PrivateTag
+(0027,"GEMS_IMAG_01",4d)	FL	SCoordOfBottomRightCorner	1	PrivateTag
+(0027,"GEMS_IMAG_01",50)	FL	TableStartLocation	1	PrivateTag
+(0027,"GEMS_IMAG_01",51)	FL	TableEndLocation	1	PrivateTag
+(0027,"GEMS_IMAG_01",52)	SH	RASLetterForSideOfImage	1	PrivateTag
+(0027,"GEMS_IMAG_01",53)	SH	RASLetterForAnteriorPosterior	1	PrivateTag
+(0027,"GEMS_IMAG_01",54)	SH	RASLetterForScoutStartLoc	1	PrivateTag
+(0027,"GEMS_IMAG_01",55)	SH	RASLetterForScoutEndLoc	1	PrivateTag
+(0027,"GEMS_IMAG_01",60)	FL	ImageDimensionX	1	PrivateTag
+(0027,"GEMS_IMAG_01",61)	FL	ImageDimensionY	1	PrivateTag
+(0027,"GEMS_IMAG_01",62)	FL	NumberOfExcitations	1	PrivateTag
+
+(0029,"GEMS_IMPS_01",04)	SL	LowerRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",05)	DS	LowerRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",06)	DS	LowerRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",07)	SL	LowerRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",08)	SH	LowerRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",09)	SH	LowerRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",0a)	SS	LowerRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",15)	SL	LowerRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",16)	SL	LowerRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",17)	SL	LowerRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",18)	SL	UpperRangeOfPixels	1	PrivateTag
+(0029,"GEMS_IMPS_01",1a)	SL	LengthOfTotalHeaderInBytes	1	PrivateTag
+(0029,"GEMS_IMPS_01",26)	SS	VersionOfHeaderStructure	1	PrivateTag
+(0029,"GEMS_IMPS_01",34)	SL	AdvantageCompOverflow	1	PrivateTag
+(0029,"GEMS_IMPS_01",35)	SL	AdvantageCompUnderflow	1	PrivateTag
+
+(0043,"GEMS_PARM_01",01)	SS	BitmapOfPrescanOptions	1	PrivateTag
+(0043,"GEMS_PARM_01",02)	SS	GradientOffsetInX	1	PrivateTag
+(0043,"GEMS_PARM_01",03)	SS	GradientOffsetInY	1	PrivateTag
+(0043,"GEMS_PARM_01",04)	SS	GradientOffsetInZ	1	PrivateTag
+(0043,"GEMS_PARM_01",05)	SS	ImageIsOriginalOrUnoriginal	1	PrivateTag
+(0043,"GEMS_PARM_01",06)	SS	NumberOfEPIShots	1	PrivateTag
+(0043,"GEMS_PARM_01",07)	SS	ViewsPerSegment	1	PrivateTag
+(0043,"GEMS_PARM_01",08)	SS	RespiratoryRateInBPM	1	PrivateTag
+(0043,"GEMS_PARM_01",09)	SS	RespiratoryTriggerPoint	1	PrivateTag
+(0043,"GEMS_PARM_01",0a)	SS	TypeOfReceiverUsed	1	PrivateTag
+(0043,"GEMS_PARM_01",0b)	DS	PeakRateOfChangeOfGradientField	1	PrivateTag
+(0043,"GEMS_PARM_01",0c)	DS	LimitsInUnitsOfPercent	1	PrivateTag
+(0043,"GEMS_PARM_01",0d)	DS	PSDEstimatedLimit	1	PrivateTag
+(0043,"GEMS_PARM_01",0e)	DS	PSDEstimatedLimitInTeslaPerSecond	1	PrivateTag
+(0043,"GEMS_PARM_01",0f)	DS	SARAvgHead	1	PrivateTag
+(0043,"GEMS_PARM_01",10)	US	WindowValue	1	PrivateTag
+(0043,"GEMS_PARM_01",11)	US	TotalInputViews	1	PrivateTag
+(0043,"GEMS_PARM_01",12)	SS	XrayChain	3	PrivateTag
+(0043,"GEMS_PARM_01",13)	SS	ReconKernelParameters	5	PrivateTag
+(0043,"GEMS_PARM_01",14)	SS	CalibrationParameters	3	PrivateTag
+(0043,"GEMS_PARM_01",15)	SS	TotalOutputViews	3	PrivateTag
+(0043,"GEMS_PARM_01",16)	SS	NumberOfOverranges	5	PrivateTag
+(0043,"GEMS_PARM_01",17)	DS	IBHImageScaleFactors	1	PrivateTag
+(0043,"GEMS_PARM_01",18)	DS	BBHCoefficients	3	PrivateTag
+(0043,"GEMS_PARM_01",19)	SS	NumberOfBBHChainsToBlend	1	PrivateTag
+(0043,"GEMS_PARM_01",1a)	SL	StartingChannelNumber	1	PrivateTag
+(0043,"GEMS_PARM_01",1b)	SS	PPScanParameters	1	PrivateTag
+(0043,"GEMS_PARM_01",1c)	SS	GEImageIntegrity	1	PrivateTag
+(0043,"GEMS_PARM_01",1d)	SS	LevelValue	1	PrivateTag
+(0043,"GEMS_PARM_01",1e)	DS	DeltaStartTime	1	PrivateTag
+(0043,"GEMS_PARM_01",1f)	SL	MaxOverrangesInAView	1	PrivateTag
+(0043,"GEMS_PARM_01",20)	DS	AvgOverrangesAllViews	1	PrivateTag
+(0043,"GEMS_PARM_01",21)	SS	CorrectedAfterglowTerms	1	PrivateTag
+(0043,"GEMS_PARM_01",25)	SS	ReferenceChannels	6	PrivateTag
+(0043,"GEMS_PARM_01",26)	US	NoViewsRefChannelsBlocked	6	PrivateTag
+(0043,"GEMS_PARM_01",27)	SH	ScanPitchRatio	1	PrivateTag
+(0043,"GEMS_PARM_01",28)	OB	UniqueImageIdentifier	1	PrivateTag
+(0043,"GEMS_PARM_01",29)	OB	HistogramTables	1	PrivateTag
+(0043,"GEMS_PARM_01",2a)	OB	UserDefinedData	1	PrivateTag
+(0043,"GEMS_PARM_01",2b)	SS	PrivateScanOptions	4	PrivateTag
+(0043,"GEMS_PARM_01",2c)	SS	EffectiveEchoSpacing	1	PrivateTag
+(0043,"GEMS_PARM_01",2d)	SH	StringSlopField1	1	PrivateTag
+(0043,"GEMS_PARM_01",2e)	SH	StringSlopField2	1	PrivateTag
+(0043,"GEMS_PARM_01",2f)	SS	RawDataType	1	PrivateTag
+(0043,"GEMS_PARM_01",30)	SS	RawDataType	1	PrivateTag
+(0043,"GEMS_PARM_01",31)	DS	RACoordOfTargetReconCentre	2	PrivateTag
+(0043,"GEMS_PARM_01",32)	SS	RawDataType	1	PrivateTag
+(0043,"GEMS_PARM_01",33)	FL	NegScanSpacing	1	PrivateTag
+(0043,"GEMS_PARM_01",34)	IS	OffsetFrequency	1	PrivateTag
+(0043,"GEMS_PARM_01",35)	UL	UserUsageTag	1	PrivateTag
+(0043,"GEMS_PARM_01",36)	UL	UserFillMapMSW	1	PrivateTag
+(0043,"GEMS_PARM_01",37)	UL	UserFillMapLSW	1	PrivateTag
+(0043,"GEMS_PARM_01",38)	FL	User25ToUser48	24	PrivateTag
+(0043,"GEMS_PARM_01",39)	IS	SlopInteger6ToSlopInteger9	4	PrivateTag
+(0043,"GEMS_PARM_01",40)	FL	TriggerOnPosition	4	PrivateTag
+(0043,"GEMS_PARM_01",41)	FL	DegreeOfRotation	4	PrivateTag
+(0043,"GEMS_PARM_01",42)	SL	DASTriggerSource	4	PrivateTag
+(0043,"GEMS_PARM_01",43)	SL	DASFpaGain	4	PrivateTag
+(0043,"GEMS_PARM_01",44)	SL	DASOutputSource	4	PrivateTag
+(0043,"GEMS_PARM_01",45)	SL	DASAdInput	4	PrivateTag
+(0043,"GEMS_PARM_01",46)	SL	DASCalMode	4	PrivateTag
+(0043,"GEMS_PARM_01",47)	SL	DASCalFrequency	4	PrivateTag
+(0043,"GEMS_PARM_01",48)	SL	DASRegXm	4	PrivateTag
+(0043,"GEMS_PARM_01",49)	SL	DASAutoZero	4	PrivateTag
+(0043,"GEMS_PARM_01",4a)	SS	StartingChannelOfView	4	PrivateTag
+(0043,"GEMS_PARM_01",4b)	SL	DASXmPattern	4	PrivateTag
+(0043,"GEMS_PARM_01",4c)	SS	TGGCTriggerMode	4	PrivateTag
+(0043,"GEMS_PARM_01",4d)	FL	StartScanToXrayOnDelay	4	PrivateTag
+(0043,"GEMS_PARM_01",4e)	FL	DurationOfXrayOn	4	PrivateTag
+(0043,"GEMS_PARM_01",60)	IS	SlopInteger10ToSlopInteger17	8	PrivateTag
+(0043,"GEMS_PARM_01",61)	UI	ScannerStudyEntityUID	1	PrivateTag
+(0043,"GEMS_PARM_01",62)	SH	ScannerStudyID	1	PrivateTag
+(0043,"GEMS_PARM_01",6f)	DS	ScannerTableEntry	3	PrivateTag
+(0043,"GEMS_PARM_01",70)	LO	ParadigmName	1	PrivateTag
+(0043,"GEMS_PARM_01",71)	ST	ParadigmDescription	1	PrivateTag
+(0043,"GEMS_PARM_01",72)	UI	ParadigmUID	1	PrivateTag
+(0043,"GEMS_PARM_01",73)	US	ExperimentType	1	PrivateTag
+(0043,"GEMS_PARM_01",74)	US	NumberOfRestVolumes	1	PrivateTag
+(0043,"GEMS_PARM_01",75)	US	NumberOfActiveVolumes	1	PrivateTag
+(0043,"GEMS_PARM_01",76)	US	NumberOfDummyScans	1	PrivateTag
+(0043,"GEMS_PARM_01",77)	SH	ApplicationName	1	PrivateTag
+(0043,"GEMS_PARM_01",78)	SH	ApplicationVersion	1	PrivateTag
+(0043,"GEMS_PARM_01",79)	US	SlicesPerVolume	1	PrivateTag
+(0043,"GEMS_PARM_01",7a)	US	ExpectedTimePoints	1	PrivateTag
+(0043,"GEMS_PARM_01",7b)	FL	RegressorValues	1-n	PrivateTag
+(0043,"GEMS_PARM_01",7c)	FL	DelayAfterSliceGroup	1	PrivateTag
+(0043,"GEMS_PARM_01",7d)	US	ReconModeFlagWord	1	PrivateTag
+(0043,"GEMS_PARM_01",7e)	LO	PACCSpecificInformation	1-n	PrivateTag
+(0043,"GEMS_PARM_01",7f)	DS	EDWIScaleFactor	1-n	PrivateTag
+(0043,"GEMS_PARM_01",80)	LO	CoilIDData	1-n	PrivateTag
+(0043,"GEMS_PARM_01",81)	LO	GECoilName	1	PrivateTag
+(0043,"GEMS_PARM_01",82)	LO	SystemConfigurationInformation	1-n	PrivateTag
+(0043,"GEMS_PARM_01",83)	DS	AssetRFactors	1-2	PrivateTag
+(0043,"GEMS_PARM_01",84)	LO	AdditionalAssetData	5-n	PrivateTag
+(0043,"GEMS_PARM_01",85)	UT	DebugDataTextFormat	1	PrivateTag
+(0043,"GEMS_PARM_01",86)	OB	DebugDataBinaryFormat	1	PrivateTag
+(0043,"GEMS_PARM_01",87)	UT	ScannerSoftwareVersionLongForm	1	PrivateTag
+(0043,"GEMS_PARM_01",88)	UI	PUREAcquisitionCalibrationSeriesUID	1	PrivateTag
+(0043,"GEMS_PARM_01",89)	LO	GoverningBodydBdtAndSARDefinition	3	PrivateTag
+(0043,"GEMS_PARM_01",8a)	CS	PrivateInPlanePhaseEncodingDirection	1	PrivateTag
+(0043,"GEMS_PARM_01",8b)	OB	FMRIBinaryDataBlock	1	PrivateTag
+(0043,"GEMS_PARM_01",8c)	DS	VoxelLocation	6	PrivateTag
+(0043,"GEMS_PARM_01",8d)	DS	SATBandLocations	7-7n	PrivateTag
+(0043,"GEMS_PARM_01",8e)	DS	SpectroPrescanValues	3	PrivateTag
+(0043,"GEMS_PARM_01",8f)	DS	SpectroParameters	3	PrivateTag
+(0043,"GEMS_PARM_01",90)	LO	SARDefinition	1-n	PrivateTag
+(0043,"GEMS_PARM_01",91)	DS	SARValue	1-n	PrivateTag
+(0043,"GEMS_PARM_01",92)	LO	ImageErrorText	1	PrivateTag
+(0043,"GEMS_PARM_01",93)	DS	SpectroQuantitationValues	1-n	PrivateTag
+(0043,"GEMS_PARM_01",94)	DS	SpectroRatioValues	1-n	PrivateTag
+(0043,"GEMS_PARM_01",95)	LO	PrescanReuseString	1	PrivateTag
+(0043,"GEMS_PARM_01",96)	CS	ContentQualification	1	PrivateTag
+(0043,"GEMS_PARM_01",97)	LO	ImageFilteringParameters	9	PrivateTag
+(0043,"GEMS_PARM_01",98)	UI	ASSETAcquisitionCalibrationSeriesUID	1	PrivateTag
+(0043,"GEMS_PARM_01",99)	LO	ExtendedOptions	1-n	PrivateTag
+(0043,"GEMS_PARM_01",9a)	IS	RxStackIdentification	1	PrivateTag
+(0043,"GEMS_PARM_01",9b)	DS	NPWFactor	1	PrivateTag
+(0043,"GEMS_PARM_01",9c)	OB	ResearchTag1	1	PrivateTag
+(0043,"GEMS_PARM_01",9d)	OB	ResearchTag2	1	PrivateTag
+(0043,"GEMS_PARM_01",9e)	OB	ResearchTag3	1	PrivateTag
+(0043,"GEMS_PARM_01",9f)	OB	ResearchTag4	1	PrivateTag
+
+(0011,"GEMS_PATI_01",10)	SS	PatientStatus	1	PrivateTag
+
+(0021,"GEMS_RELA_01",03)	SS	SeriesFromWhichPrescribed	1	PrivateTag
+(0021,"GEMS_RELA_01",05)	SH	GenesisVersionNow	1	PrivateTag
+(0021,"GEMS_RELA_01",07)	UL	SeriesRecordChecksum	1	PrivateTag
+(0021,"GEMS_RELA_01",15)	US	Unknown	1	PrivateTag
+(0021,"GEMS_RELA_01",16)	SS	Unknown	1	PrivateTag
+(0021,"GEMS_RELA_01",18)	SH	GenesisVersionNow	1	PrivateTag
+(0021,"GEMS_RELA_01",19)	UL	AcqReconRecordChecksum	1	PrivateTag
+(0021,"GEMS_RELA_01",20)	DS	TableStartLocation	1	PrivateTag
+(0021,"GEMS_RELA_01",35)	SS	SeriesFromWhichPrescribed	1	PrivateTag
+(0021,"GEMS_RELA_01",36)	SS	ImageFromWhichPrescribed	1	PrivateTag
+(0021,"GEMS_RELA_01",37)	SS	ScreenFormat	1	PrivateTag
+(0021,"GEMS_RELA_01",4a)	LO	AnatomicalReferenceForScout	1	PrivateTag
+(0021,"GEMS_RELA_01",4e)	US	Unknown	1	PrivateTag
+(0021,"GEMS_RELA_01",4f)	SS	LocationsInAcquisition	1	PrivateTag
+(0021,"GEMS_RELA_01",50)	SS	GraphicallyPrescribed	1	PrivateTag
+(0021,"GEMS_RELA_01",51)	DS	RotationFromSourceXRot	1	PrivateTag
+(0021,"GEMS_RELA_01",52)	DS	RotationFromSourceYRot	1	PrivateTag
+(0021,"GEMS_RELA_01",53)	DS	RotationFromSourceZRot	1	PrivateTag
+(0021,"GEMS_RELA_01",54)	SH	ImagePosition	3	PrivateTag
+(0021,"GEMS_RELA_01",55)	SH	ImageOrientation	6	PrivateTag
+(0021,"GEMS_RELA_01",56)	SL	IntegerSlop	1	PrivateTag
+(0021,"GEMS_RELA_01",57)	SL	IntegerSlop	1	PrivateTag
+(0021,"GEMS_RELA_01",58)	SL	IntegerSlop	1	PrivateTag
+(0021,"GEMS_RELA_01",59)	SL	IntegerSlop	1	PrivateTag
+(0021,"GEMS_RELA_01",5a)	SL	IntegerSlop	1	PrivateTag
+(0021,"GEMS_RELA_01",5b)	DS	FloatSlop	1	PrivateTag
+(0021,"GEMS_RELA_01",5c)	DS	FloatSlop	1	PrivateTag
+(0021,"GEMS_RELA_01",5d)	DS	FloatSlop	1	PrivateTag
+(0021,"GEMS_RELA_01",5e)	DS	FloatSlop	1	PrivateTag
+(0021,"GEMS_RELA_01",5f)	DS	FloatSlop	1	PrivateTag
+(0021,"GEMS_RELA_01",70)	LT	Unknown	1	PrivateTag
+(0021,"GEMS_RELA_01",71)	LT	Unknown	1	PrivateTag
+(0021,"GEMS_RELA_01",81)	DS	AutoWindowLevelAlpha	1	PrivateTag
+(0021,"GEMS_RELA_01",82)	DS	AutoWindowLevelBeta	1	PrivateTag
+(0021,"GEMS_RELA_01",83)	DS	AutoWindowLevelWindow	1	PrivateTag
+(0021,"GEMS_RELA_01",84)	DS	AutoWindowLevelLevel	1	PrivateTag
+(0021,"GEMS_RELA_01",90)	SS	TubeFocalSpotPosition	1	PrivateTag
+(0021,"GEMS_RELA_01",91)	SS	BiopsyPosition	1	PrivateTag
+(0021,"GEMS_RELA_01",92)	FL	BiopsyTLocation	1	PrivateTag
+(0021,"GEMS_RELA_01",93)	FL	BiopsyRefLocation	1	PrivateTag
+
+(0045,"GEMS_SENO_02",04)	CS	AES	1	PrivateTag
+(0045,"GEMS_SENO_02",06)	DS	Angulation	1	PrivateTag
+(0045,"GEMS_SENO_02",09)	DS	RealMagnificationFactor	1	PrivateTag
+(0045,"GEMS_SENO_02",0b)	CS	SenographType	1	PrivateTag
+(0045,"GEMS_SENO_02",0c)	DS	IntegrationTime	1	PrivateTag
+(0045,"GEMS_SENO_02",0d)	DS	ROIOriginXY	1	PrivateTag
+(0045,"GEMS_SENO_02",11)	DS	ReceptorSizeCmXY	2	PrivateTag
+(0045,"GEMS_SENO_02",12)	IS	ReceptorSizePixelsXY	2	PrivateTag
+(0045,"GEMS_SENO_02",13)	ST	Screen	1	PrivateTag
+(0045,"GEMS_SENO_02",14)	DS	PixelPitchMicrons	1	PrivateTag
+(0045,"GEMS_SENO_02",15)	IS	PixelDepthBits	1	PrivateTag
+(0045,"GEMS_SENO_02",16)	IS	BinningFactorXY	2	PrivateTag
+(0045,"GEMS_SENO_02",1B)	CS	ClinicalView	1	PrivateTag
+(0045,"GEMS_SENO_02",1D)	DS	MeanOfRawGrayLevels	1	PrivateTag
+(0045,"GEMS_SENO_02",1E)	DS	MeanOfOffsetGrayLevels	1	PrivateTag
+(0045,"GEMS_SENO_02",1F)	DS	MeanOfCorrectedGrayLevels	1	PrivateTag
+(0045,"GEMS_SENO_02",20)	DS	MeanOfRegionGrayLevels	1	PrivateTag
+(0045,"GEMS_SENO_02",21)	DS	MeanOfLogRegionGrayLevels	1	PrivateTag
+(0045,"GEMS_SENO_02",22)	DS	StandardDeviationOfRawGrayLevels	1	PrivateTag
+(0045,"GEMS_SENO_02",23)	DS	StandardDeviationOfCorrectedGrayLevels	1	PrivateTag
+(0045,"GEMS_SENO_02",24)	DS	StandardDeviationOfRegionGrayLevels	1	PrivateTag
+(0045,"GEMS_SENO_02",25)	DS	StandardDeviationOfLogRegionGrayLevels	1	PrivateTag
+(0045,"GEMS_SENO_02",26)	OB	MAOBuffer	1	PrivateTag
+(0045,"GEMS_SENO_02",27)	IS	SetNumber	1	PrivateTag
+(0045,"GEMS_SENO_02",28)	CS	WindowingType	1	PrivateTag
+(0045,"GEMS_SENO_02",29)	DS	WindowingParameters	1-n	PrivateTag
+(0045,"GEMS_SENO_02",2a)	IS	CrosshairCursorXCoordinates	1	PrivateTag
+(0045,"GEMS_SENO_02",2b)	IS	CrosshairCursorYCoordinates	1	PrivateTag
+(0045,"GEMS_SENO_02",39)	US	VignetteRows	1	PrivateTag
+(0045,"GEMS_SENO_02",3a)	US	VignetteColumns	1	PrivateTag
+(0045,"GEMS_SENO_02",3b)	US	VignetteBitsAllocated	1	PrivateTag
+(0045,"GEMS_SENO_02",3c)	US	VignetteBitsStored	1	PrivateTag
+(0045,"GEMS_SENO_02",3d)	US	VignetteHighBit	1	PrivateTag
+(0045,"GEMS_SENO_02",3e)	US	VignettePixelRepresentation	1	PrivateTag
+(0045,"GEMS_SENO_02",3f)	OB	VignettePixelData	1	PrivateTag
+
+(0025,"GEMS_SERS_01",06)	SS	LastPulseSequenceUsed	1	PrivateTag
+(0025,"GEMS_SERS_01",07)	SL	ImagesInSeries	1	PrivateTag
+(0025,"GEMS_SERS_01",10)	SL	LandmarkCounter	1	PrivateTag
+(0025,"GEMS_SERS_01",11)	SS	NumberOfAcquisitions	1	PrivateTag
+(0025,"GEMS_SERS_01",14)	SL	IndicatesNumberOfUpdatesToHeader	1	PrivateTag
+(0025,"GEMS_SERS_01",17)	SL	SeriesCompleteFlag	1	PrivateTag
+(0025,"GEMS_SERS_01",18)	SL	NumberOfImagesArchived	1	PrivateTag
+(0025,"GEMS_SERS_01",19)	SL	LastImageNumberUsed	1	PrivateTag
+(0025,"GEMS_SERS_01",1a)	SH	PrimaryReceiverSuiteAndHost	1	PrivateTag
+
+(0023,"GEMS_STDY_01",01)	SL	NumberOfSeriesInStudy	1	PrivateTag
+(0023,"GEMS_STDY_01",02)	SL	NumberOfUnarchivedSeries	1	PrivateTag
+(0023,"GEMS_STDY_01",10)	SS	ReferenceImageField	1	PrivateTag
+(0023,"GEMS_STDY_01",50)	SS	SummaryImage	1	PrivateTag
+(0023,"GEMS_STDY_01",70)	FD	StartTimeSecsInFirstAxial	1	PrivateTag
+(0023,"GEMS_STDY_01",74)	SL	NumberOfUpdatesToHeader	1	PrivateTag
+(0023,"GEMS_STDY_01",7d)	SS	IndicatesIfStudyHasCompleteInfo	1	PrivateTag
+
+(0033,"GEMS_YMHD_01",05)	UN	Unknown	1	PrivateTag
+(0033,"GEMS_YMHD_01",06)	UN	Unknown	1	PrivateTag
+
+(0019,"GE_GENESIS_REV3.0",39)	SS	AxialType	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",8f)	SS	SwapPhaseFrequency	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",9c)	SS	PulseSequenceName	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",9f)	SS	CoilType	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",a4)	SS	SATFatWaterBone	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",c0)	SS	BitmapOfSATSelections	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",c1)	SS	SurfaceCoilIntensityCorrectionFlag	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",cb)	SS	PhaseContrastFlowAxis	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",cc)	SS	PhaseContrastVelocityEncoding	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",d5)	SS	FractionalEcho	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",d8)	SS	VariableEchoFlag	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",d9)	DS	ConcatenatedSat	1	PrivateTag
+(0019,"GE_GENESIS_REV3.0",f2)	SS	NumberOfPhases	1	PrivateTag
+(0043,"GE_GENESIS_REV3.0",1e)	DS	DeltaStartTime	1	PrivateTag
+(0043,"GE_GENESIS_REV3.0",27)	SH	ScanPitchRatio	1	PrivateTag
+
+(0029,"INTELERAD MEDICAL SYSTEMS",01)	FD	ImageCompressionFraction	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",02)	FD	ImageQuality	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",03)	FD	ImageBytesTransferred	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",10)	SH	J2cParameterType	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",11)	US	J2cPixelRepresentation	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",12)	US	J2cBitsAllocated	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",13)	US	J2cPixelShiftValue	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",14)	US	J2cPlanarConfiguration	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",15)	DS	J2cRescaleIntercept	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",20)	LO	PixelDataMD5SumPerFrame	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",21)	US	HistogramPercentileLabels	1	PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",22)	FD	HistogramPercentileValues	1	PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",01)	LO	InstitutionCode	1	PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",02)	LO	RoutedTransferAE	1	PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",03)	LO	SourceAE	1	PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",04)	SH	DeferredValidation	1	PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",05)	LO	SeriesOwner	1	PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",06)	LO	OrderGroupNumber	1	PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",07)	SH	StrippedPixelData	1	PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",08)	SH	PendingMoveRequest	1	PrivateTag
+
+(0041,"INTEGRIS 1.0",20)	FL	AccumulatedFluoroscopyDose	1	PrivateTag
+(0041,"INTEGRIS 1.0",30)	FL	AccumulatedExposureDose	1	PrivateTag
+(0041,"INTEGRIS 1.0",40)	FL	TotalDose	1	PrivateTag
+(0041,"INTEGRIS 1.0",41)	FL	TotalNumberOfFrames	1	PrivateTag
+(0041,"INTEGRIS 1.0",50)	SQ	ExposureInformationSequence	1	PrivateTag
+(0009,"INTEGRIS 1.0",08)	CS	ExposureChannel	1-n	PrivateTag
+(0009,"INTEGRIS 1.0",32)	TM	ExposureStartTime	1	PrivateTag
+(0019,"INTEGRIS 1.0",00)	LO	APRName	1	PrivateTag
+(0019,"INTEGRIS 1.0",40)	DS	FrameRate	1	PrivateTag
+(0021,"INTEGRIS 1.0",12)	IS	ExposureNumber	1	PrivateTag
+(0029,"INTEGRIS 1.0",08)	IS	NumberOfExposureResults	1	PrivateTag
+
+(0029,"ISG shadow",70)	IS	Unknown	1	PrivateTag
+(0029,"ISG shadow",80)	IS	Unknown	1	PrivateTag
+(0029,"ISG shadow",90)	IS	Unknown	1	PrivateTag
+
+(0009,"ISI",01)	UN	SIENETGeneralPurposeIMGEF	1	PrivateTag
+
+(0009,"MERGE TECHNOLOGIES, INC.",00)	OB	Unknown	1	PrivateTag
+
+(0029,"OCULUS Optikgeraete GmbH",1010)	OB	OriginalMeasuringData	1	PrivateTag
+(0029,"OCULUS Optikgeraete GmbH",1012)	UL	OriginalMeasuringDataLength	1	PrivateTag
+(0029,"OCULUS Optikgeraete GmbH",1020)	OB	OriginalMeasuringRawData	1	PrivateTag
+(0029,"OCULUS Optikgeraete GmbH",1022)	UL	OriginalMeasuringRawDataLength	1	PrivateTag
+
+(0041,"PAPYRUS 3.0",00)	LT	PapyrusComments	1	PrivateTag
+(0041,"PAPYRUS 3.0",10)	SQ	PointerSequence	1	PrivateTag
+(0041,"PAPYRUS 3.0",11)	UL	ImagePointer	1	PrivateTag
+(0041,"PAPYRUS 3.0",12)	UL	PixelOffset	1	PrivateTag
+(0041,"PAPYRUS 3.0",13)	SQ	ImageIdentifierSequence	1	PrivateTag
+(0041,"PAPYRUS 3.0",14)	SQ	ExternalFileReferenceSequence	1	PrivateTag
+(0041,"PAPYRUS 3.0",15)	US	NumberOfImages	1	PrivateTag
+(0041,"PAPYRUS 3.0",21)	UI	ReferencedSOPClassUID	1	PrivateTag
+(0041,"PAPYRUS 3.0",22)	UI	ReferencedSOPInstanceUID	1	PrivateTag
+(0041,"PAPYRUS 3.0",31)	LT	ReferencedFileName	1	PrivateTag
+(0041,"PAPYRUS 3.0",32)	LT	ReferencedFilePath	1-n	PrivateTag
+(0041,"PAPYRUS 3.0",41)	UI	ReferencedImageSOPClassUID	1	PrivateTag
+(0041,"PAPYRUS 3.0",42)	UI	ReferencedImageSOPInstanceUID	1	PrivateTag
+(0041,"PAPYRUS 3.0",50)	SQ	ImageSequence	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",00)	IS	OverlayID	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",01)	LT	LinkedOverlays	1-n	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",10)	US	OverlayRows	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",11)	US	OverlayColumns	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",40)	LO	OverlayType	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",50)	US	OverlayOrigin	1-n	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",60)	LO	Editable	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",70)	LO	OverlayFont	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",72)	LO	OverlayStyle	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",74)	US	OverlayFontSize	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",76)	LO	OverlayColor	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",78)	US	ShadowSize	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",80)	LO	FillPattern	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",82)	US	OverlayPenSize	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",a0)	LO	Label	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",a2)	LT	PostItText	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",a4)	US	AnchorPoint	2	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",b0)	LO	ROIType	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",b2)	LT	AttachedAnnotation	1	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",ba)	US	ContourPoints	1-n	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",bc)	US	MaskData	1-n	PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",c0)	SQ	UINOverlaySequence	1	PrivateTag
+
+(0009,"PAPYRUS",00)	LT	OriginalFileName	1	PrivateTag
+(0009,"PAPYRUS",10)	LT	OriginalFileLocation	1	PrivateTag
+(0009,"PAPYRUS",18)	LT	DataSetIdentifier	1	PrivateTag
+(0041,"PAPYRUS",00)	LT	PapyrusComments	1-n	PrivateTag
+(0041,"PAPYRUS",10)	US	FolderType	1	PrivateTag
+(0041,"PAPYRUS",11)	LT	PatientFolderDataSetID	1	PrivateTag
+(0041,"PAPYRUS",20)	LT	FolderName	1	PrivateTag
+(0041,"PAPYRUS",30)	DA	CreationDate	1	PrivateTag
+(0041,"PAPYRUS",32)	TM	CreationTime	1	PrivateTag
+(0041,"PAPYRUS",34)	DA	ModifiedDate	1	PrivateTag
+(0041,"PAPYRUS",36)	TM	ModifiedTime	1	PrivateTag
+(0041,"PAPYRUS",40)	LT	OwnerName	1-n	PrivateTag
+(0041,"PAPYRUS",50)	LT	FolderStatus	1	PrivateTag
+(0041,"PAPYRUS",60)	UL	NumberOfImages	1	PrivateTag
+(0041,"PAPYRUS",62)	UL	NumberOfOther	1	PrivateTag
+(0041,"PAPYRUS",a0)	LT	ExternalFolderElementDSID	1-n	PrivateTag
+(0041,"PAPYRUS",a1)	US	ExternalFolderElementDataSetType	1-n	PrivateTag
+(0041,"PAPYRUS",a2)	LT	ExternalFolderElementFileLocation	1-n	PrivateTag
+(0041,"PAPYRUS",a3)	UL	ExternalFolderElementLength	1-n	PrivateTag
+(0041,"PAPYRUS",b0)	LT	InternalFolderElementDSID	1-n	PrivateTag
+(0041,"PAPYRUS",b1)	US	InternalFolderElementDataSetType	1-n	PrivateTag
+(0041,"PAPYRUS",b2)	UL	InternalOffsetToDataSet	1-n	PrivateTag
+(0041,"PAPYRUS",b3)	UL	InternalOffsetToImage	1-n
+
+# Note: Some Philips devices use these private tags with reservation value
+# "Philips Imaging DD 001", others use "PHILIPS IMAGING DD 001". All attributes
+# should thus be present twice in this dictionary, once for each spelling variant.
+#
+(2001,"Philips Imaging DD 001",01)	FL	ChemicalShift	1	PrivateTag
+(2001,"Philips Imaging DD 001",02)	IS	ChemicalShiftNumberMR	1	PrivateTag
+(2001,"Philips Imaging DD 001",03)	FL	DiffusionBFactor	1	PrivateTag
+(2001,"Philips Imaging DD 001",04)	CS	DiffusionDirection	1	PrivateTag
+(2001,"Philips Imaging DD 001",06)	CS	ImageEnhanced	1	PrivateTag
+(2001,"Philips Imaging DD 001",07)	CS	ImageTypeEDES	1	PrivateTag
+(2001,"Philips Imaging DD 001",08)	IS	PhaseNumber	1	PrivateTag
+(2001,"Philips Imaging DD 001",09)	FL	ImagePrepulseDelay	1	PrivateTag
+(2001,"Philips Imaging DD 001",0a)	IS	SliceNumberMR	1	PrivateTag
+(2001,"Philips Imaging DD 001",0b)	CS	SliceOrientation	1	PrivateTag
+(2001,"Philips Imaging DD 001",0c)	CS	ArrhythmiaRejection	1	PrivateTag
+(2001,"Philips Imaging DD 001",0e)	CS	CardiacCycled	1	PrivateTag
+(2001,"Philips Imaging DD 001",0f)	SS	CardiacGateWidth	1	PrivateTag
+(2001,"Philips Imaging DD 001",10)	CS	CardiacSync	1	PrivateTag
+(2001,"Philips Imaging DD 001",11)	FL	DiffusionEchoTime	1	PrivateTag
+(2001,"Philips Imaging DD 001",12)	CS	DynamicSeries	1	PrivateTag
+(2001,"Philips Imaging DD 001",13)	SL	EPIFactor	1	PrivateTag
+(2001,"Philips Imaging DD 001",14)	SL	NumberOfEchoes	1	PrivateTag
+(2001,"Philips Imaging DD 001",15)	SS	NumberOfLocations	1	PrivateTag
+(2001,"Philips Imaging DD 001",16)	SS	NumberOfPCDirections	1	PrivateTag
+(2001,"Philips Imaging DD 001",17)	SL	NumberOfPhasesMR	1	PrivateTag
+(2001,"Philips Imaging DD 001",18)	SL	NumberOfSlicesMR	1	PrivateTag
+(2001,"Philips Imaging DD 001",19)	CS	PartialMatrixScanned	1	PrivateTag
+(2001,"Philips Imaging DD 001",1a)	FL	PCVelocity	1-n	PrivateTag
+(2001,"Philips Imaging DD 001",1b)	FL	PrepulseDelay	1	PrivateTag
+(2001,"Philips Imaging DD 001",1c)	CS	PrepulseType	1	PrivateTag
+(2001,"Philips Imaging DD 001",1d)	IS	ReconstructionNumberMR	1	PrivateTag
+(2001,"Philips Imaging DD 001",1f)	CS	RespirationSync	1	PrivateTag
+(2001,"Philips Imaging DD 001",20)	LO	ScanningTechnique	1	PrivateTag
+(2001,"Philips Imaging DD 001",21)	CS	SPIR	1	PrivateTag
+(2001,"Philips Imaging DD 001",22)	FL	WaterFatShift	1	PrivateTag
+(2001,"Philips Imaging DD 001",23)	DS	FlipAnglePhilips	1	PrivateTag
+(2001,"Philips Imaging DD 001",24)	CS	SeriesIsInteractive	1	PrivateTag
+(2001,"Philips Imaging DD 001",25)	SH	EchoTimeDisplayMR	1	PrivateTag
+(2001,"Philips Imaging DD 001",26)	CS	PresentationStateSubtractionActive	1	PrivateTag
+(2001,"Philips Imaging DD 001",2d)	SS	StackNumberOfSlices	1	PrivateTag
+(2001,"Philips Imaging DD 001",32)	FL	StackRadialAngle	1	PrivateTag
+(2001,"Philips Imaging DD 001",33)	CS	StackRadialAxis	1	PrivateTag
+(2001,"Philips Imaging DD 001",35)	SS	StackSliceNumber	1	PrivateTag
+(2001,"Philips Imaging DD 001",36)	CS	StackType	1	PrivateTag
+(2001,"Philips Imaging DD 001",3f)	CS	ZoomMode	1	PrivateTag
+(2001,"Philips Imaging DD 001",58)	UL	ContrastTransferTaste	1	PrivateTag
+(2001,"Philips Imaging DD 001",5f)	SQ	StackSequence	1	PrivateTag
+(2001,"Philips Imaging DD 001",60)	SL	NumberOfStacks	1	PrivateTag
+(2001,"Philips Imaging DD 001",61)	CS	SeriesTransmitted	1	PrivateTag
+(2001,"Philips Imaging DD 001",62)	CS	SeriesCommitted	1	PrivateTag
+(2001,"Philips Imaging DD 001",63)	CS	ExaminationSource	1	PrivateTag
+(2001,"Philips Imaging DD 001",67)	CS	LinearPresentationGLTrafoShapeSub	1	PrivateTag
+(2001,"Philips Imaging DD 001",77)	CS	GLTrafoType	1	PrivateTag
+(2001,"Philips Imaging DD 001",7b)	IS	AcquisitionNumber	1	PrivateTag
+(2001,"Philips Imaging DD 001",81)	IS	NumberOfDynamicScans	1	PrivateTag
+(2001,"Philips Imaging DD 001",9f)	US	PixelProcessingKernelSize	1	PrivateTag
+(2001,"Philips Imaging DD 001",a1)	CS	IsRawImage	1	PrivateTag
+(2001,"Philips Imaging DD 001",f1)	FL	ProspectiveMotionCorrection	1	PrivateTag
+(2001,"Philips Imaging DD 001",f2)	FL	RetrospectiveMotionCorrection	1	PrivateTag
+
+# Note: Some Philips devices use these private tags with reservation value
+# "Philips Imaging DD 001", others use "PHILIPS IMAGING DD 001". All attributes
+# should thus be present twice in this dictionary, once for each spelling variant.
+#
+(2001,"PHILIPS IMAGING DD 001",01)	FL	ChemicalShift	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",02)	IS	ChemicalShiftNumberMR	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",03)	FL	DiffusionBFactor	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",04)	CS	DiffusionDirection	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",06)	CS	ImageEnhanced	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",07)	CS	ImageTypeEDES	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",08)	IS	PhaseNumber	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",09)	FL	ImagePrepulseDelay	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",0a)	IS	SliceNumberMR	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",0b)	CS	SliceOrientation	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",0c)	CS	ArrhythmiaRejection	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",0e)	CS	CardiacCycled	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",0f)	SS	CardiacGateWidth	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",10)	CS	CardiacSync	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",11)	FL	DiffusionEchoTime	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",12)	CS	DynamicSeries	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",13)	SL	EPIFactor	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",14)	SL	NumberOfEchoes	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",15)	SS	NumberOfLocations	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",16)	SS	NumberOfPCDirections	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",17)	SL	NumberOfPhasesMR	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",18)	SL	NumberOfSlicesMR	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",19)	CS	PartialMatrixScanned	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",1a)	FL	PCVelocity	1-n	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",1b)	FL	PrepulseDelay	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",1c)	CS	PrepulseType	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",1d)	IS	ReconstructionNumberMR	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",1f)	CS	RespirationSync	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",20)	LO	ScanningTechnique	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",21)	CS	SPIR	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",22)	FL	WaterFatShift	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",23)	DS	FlipAnglePhilips	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",24)	CS	SeriesIsInteractive	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",25)	SH	EchoTimeDisplayMR	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",26)	CS	PresentationStateSubtractionActive	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",2d)	SS	StackNumberOfSlices	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",32)	FL	StackRadialAngle	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",33)	CS	StackRadialAxis	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",35)	SS	StackSliceNumber	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",36)	CS	StackType	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",3f)	CS	ZoomMode	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",58)	UL	ContrastTransferTaste	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",5f)	SQ	StackSequence	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",60)	SL	NumberOfStacks	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",61)	CS	SeriesTransmitted	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",62)	CS	SeriesCommitted	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",63)	CS	ExaminationSource	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",67)	CS	LinearPresentationGLTrafoShapeSub	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",77)	CS	GLTrafoType	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",7b)	IS	AcquisitionNumber	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",81)	IS	NumberOfDynamicScans	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",9f)	US	PixelProcessingKernelSize	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",a1)	CS	IsRawImage	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",f1)	FL	ProspectiveMotionCorrection	1	PrivateTag
+(2001,"PHILIPS IMAGING DD 001",f2)	FL	RetrospectiveMotionCorrection	1	PrivateTag
+
+# Note: Some Philips devices use these private tags with reservation value
+# "Philips MR Imaging DD 001", others use "PHILIPS MR IMAGING DD 001". All attributes
+# should thus be present twice in this dictionary, once for each spelling variant.
+#
+(2005,"Philips MR Imaging DD 001",05)	CS	SynergyReconstructionType	1	PrivateTag
+(2005,"Philips MR Imaging DD 001",1e)	SH	MIPProtocol	1	PrivateTag
+(2005,"Philips MR Imaging DD 001",1f)	SH	MPRProtocol	1	PrivateTag
+(2005,"Philips MR Imaging DD 001",20)	SL	NumberOfChemicalShifts	1	PrivateTag
+(2005,"Philips MR Imaging DD 001",2d)	SS	NumberOfStackSlices	1	PrivateTag
+(2005,"Philips MR Imaging DD 001",83)	SQ	Unknown	1	PrivateTag
+(2005,"Philips MR Imaging DD 001",a1)	CS	SyncraScanType	1	PrivateTag
+(2005,"Philips MR Imaging DD 001",b0)	FL	DiffusionDirectionRL	1	PrivateTag
+(2005,"Philips MR Imaging DD 001",b1)	FL	DiffusionDirectionAP	1	PrivateTag
+(2005,"Philips MR Imaging DD 001",b2)	FL	DiffusionDirectionFH	1	PrivateTag
+
+(2005,"Philips MR Imaging DD 005",02)	SQ	Unknown	1	PrivateTag
+
+# Note: Some Philips devices use these private tags with reservation value
+# "Philips MR Imaging DD 001", others use "PHILIPS MR IMAGING DD 001". All attributes
+# should thus be present twice in this dictionary, once for each spelling variant.
+#
+(2005,"PHILIPS MR IMAGING DD 001",05)	CS	SynergyReconstructionType	1	PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",1e)	SH	MIPProtocol	1	PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",1f)	SH	MPRProtocol	1	PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",20)	SL	NumberOfChemicalShifts	1	PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",2d)	SS	NumberOfStackSlices	1	PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",83)	SQ	Unknown	1	PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",a1)	CS	SyncraScanType	1	PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",b0)	FL	DiffusionDirectionRL	1	PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",b1)	FL	DiffusionDirectionAP	1	PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",b2)	FL	DiffusionDirectionFH	1	PrivateTag
+
+(0019,"PHILIPS MR R5.5/PART",1000)	DS	FieldOfView	1	PrivateTag
+(0019,"PHILIPS MR R5.6/PART",1000)	DS	FieldOfView	1	PrivateTag
+
+(0019,"PHILIPS MR SPECTRO;1",01)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",02)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",03)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",04)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",05)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",06)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",07)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",08)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",09)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",10)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",12)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",13)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",14)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",15)	US	Unknown	1-n	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",16)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",17)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",18)	UN	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",20)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",21)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",22)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",23)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",24)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",25)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",26)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",27)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",28)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",29)	IS	Unknown	1-n	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",31)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",32)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",41)	LT	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",42)	IS	Unknown	2	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",43)	IS	Unknown	2	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",45)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",46)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",47)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",48)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",49)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",50)	UN	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",60)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",61)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",70)	UN	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",71)	IS	Unknown	1-n	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",72)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",73)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",74)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",76)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",77)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",78)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",79)	US	Unknown	1	PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",80)	IS	Unknown	1	PrivateTag
+
+(0009,"PHILIPS MR",10)	LO	SPIRelease	1	PrivateTag
+(0009,"PHILIPS MR",12)	LO	Unknown	1	PrivateTag
+
+(0019,"PHILIPS MR/LAST",09)	DS	MainMagneticField	1	PrivateTag
+(0019,"PHILIPS MR/LAST",0e)	IS	FlowCompensation	1	PrivateTag
+(0019,"PHILIPS MR/LAST",b1)	IS	MinimumRRInterval	1	PrivateTag
+(0019,"PHILIPS MR/LAST",b2)	IS	MaximumRRInterval	1	PrivateTag
+(0019,"PHILIPS MR/LAST",b3)	IS	NumberOfRejections	1	PrivateTag
+(0019,"PHILIPS MR/LAST",b4)	IS	NumberOfRRIntervals	1-n	PrivateTag
+(0019,"PHILIPS MR/LAST",b5)	IS	ArrhythmiaRejection	1	PrivateTag
+(0019,"PHILIPS MR/LAST",c0)	DS	Unknown	1-n	PrivateTag
+(0019,"PHILIPS MR/LAST",c6)	IS	CycledMultipleSlice	1	PrivateTag
+(0019,"PHILIPS MR/LAST",ce)	IS	REST	1	PrivateTag
+(0019,"PHILIPS MR/LAST",d5)	DS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/LAST",d6)	IS	FourierInterpolation	1	PrivateTag
+(0019,"PHILIPS MR/LAST",d9)	IS	Unknown	1-n	PrivateTag
+(0019,"PHILIPS MR/LAST",e0)	IS	Prepulse	1	PrivateTag
+(0019,"PHILIPS MR/LAST",e1)	DS	PrepulseDelay	1	PrivateTag
+(0019,"PHILIPS MR/LAST",e2)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/LAST",e3)	DS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/LAST",f0)	LT	WSProtocolString1	1	PrivateTag
+(0019,"PHILIPS MR/LAST",f1)	LT	WSProtocolString2	1	PrivateTag
+(0019,"PHILIPS MR/LAST",f2)	LT	WSProtocolString3	1	PrivateTag
+(0019,"PHILIPS MR/LAST",f3)	LT	WSProtocolString4	1	PrivateTag
+(0021,"PHILIPS MR/LAST",00)	IS	Unknown	1	PrivateTag
+(0021,"PHILIPS MR/LAST",10)	IS	Unknown	1	PrivateTag
+(0021,"PHILIPS MR/LAST",20)	IS	Unknown	1	PrivateTag
+(0021,"PHILIPS MR/LAST",21)	DS	SliceGap	1	PrivateTag
+(0021,"PHILIPS MR/LAST",22)	DS	StackRadialAngle	1	PrivateTag
+(0027,"PHILIPS MR/LAST",00)	US	Unknown	1	PrivateTag
+(0027,"PHILIPS MR/LAST",11)	US	Unknown	1-n	PrivateTag
+(0027,"PHILIPS MR/LAST",12)	DS	Unknown	1-n	PrivateTag
+(0027,"PHILIPS MR/LAST",13)	DS	Unknown	1-n	PrivateTag
+(0027,"PHILIPS MR/LAST",14)	DS	Unknown	1-n	PrivateTag
+(0027,"PHILIPS MR/LAST",15)	DS	Unknown	1-n	PrivateTag
+(0027,"PHILIPS MR/LAST",16)	LO	Unknown	1	PrivateTag
+(0029,"PHILIPS MR/LAST",10)	DS	FPMin	1	PrivateTag
+(0029,"PHILIPS MR/LAST",20)	DS	FPMax	1	PrivateTag
+(0029,"PHILIPS MR/LAST",30)	DS	ScaledMinimum	1	PrivateTag
+(0029,"PHILIPS MR/LAST",40)	DS	ScaledMaximum	1	PrivateTag
+(0029,"PHILIPS MR/LAST",50)	DS	WindowMinimum	1	PrivateTag
+(0029,"PHILIPS MR/LAST",60)	DS	WindowMaximum	1	PrivateTag
+(0029,"PHILIPS MR/LAST",61)	IS	Unknown	1	PrivateTag
+(0029,"PHILIPS MR/LAST",70)	DS	Unknown	1	PrivateTag
+(0029,"PHILIPS MR/LAST",71)	DS	Unknown	1	PrivateTag
+(0029,"PHILIPS MR/LAST",72)	IS	Unknown	1	PrivateTag
+(0029,"PHILIPS MR/LAST",80)	IS	ViewCenter	1	PrivateTag
+(0029,"PHILIPS MR/LAST",81)	IS	ViewSize	1	PrivateTag
+(0029,"PHILIPS MR/LAST",82)	IS	ViewZoom	1	PrivateTag
+(0029,"PHILIPS MR/LAST",83)	IS	ViewTransform	1	PrivateTag
+(6001,"PHILIPS MR/LAST",00)	LT	Unknown	1	PrivateTag
+
+(0019,"PHILIPS MR/PART",1000)	DS	FieldOfView	1	PrivateTag
+(0019,"PHILIPS MR/PART",1005)	DS	CCAngulation	1	PrivateTag
+(0019,"PHILIPS MR/PART",1006)	DS	APAngulation	1	PrivateTag
+(0019,"PHILIPS MR/PART",1007)	DS	LRAngulation	1	PrivateTag
+(0019,"PHILIPS MR/PART",1008)	IS	PatientPosition	1	PrivateTag
+(0019,"PHILIPS MR/PART",1009)	IS	PatientOrientation	1	PrivateTag
+(0019,"PHILIPS MR/PART",100a)	IS	SliceOrientation	1	PrivateTag
+(0019,"PHILIPS MR/PART",100b)	DS	LROffcenter	1	PrivateTag
+(0019,"PHILIPS MR/PART",100c)	DS	CCOffcenter	1	PrivateTag
+(0019,"PHILIPS MR/PART",100d)	DS	APOffcenter	1	PrivateTag
+(0019,"PHILIPS MR/PART",100e)	DS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",100f)	IS	NumberOfSlices	1	PrivateTag
+(0019,"PHILIPS MR/PART",1010)	DS	SliceFactor	1	PrivateTag
+(0019,"PHILIPS MR/PART",1011)	DS	EchoTimes	1-n	PrivateTag
+(0019,"PHILIPS MR/PART",1015)	IS	DynamicStudy	1	PrivateTag
+(0019,"PHILIPS MR/PART",1018)	DS	HeartbeatInterval	1	PrivateTag
+(0019,"PHILIPS MR/PART",1019)	DS	RepetitionTimeFFE	1	PrivateTag
+(0019,"PHILIPS MR/PART",101a)	DS	FFEFlipAngle	1	PrivateTag
+(0019,"PHILIPS MR/PART",101b)	IS	NumberOfScans	1	PrivateTag
+(0019,"PHILIPS MR/PART",1021)	DS	Unknown	1-n	PrivateTag
+(0019,"PHILIPS MR/PART",1022)	DS	DynamicScanTimeBegin	1	PrivateTag
+(0019,"PHILIPS MR/PART",1024)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",1064)	DS	RepetitionTimeSE	1	PrivateTag
+(0019,"PHILIPS MR/PART",1065)	DS	RepetitionTimeIR	1	PrivateTag
+(0019,"PHILIPS MR/PART",1069)	IS	NumberOfPhases	1	PrivateTag
+(0019,"PHILIPS MR/PART",106a)	IS	CardiacFrequency	1	PrivateTag
+(0019,"PHILIPS MR/PART",106b)	DS	InversionDelay	1	PrivateTag
+(0019,"PHILIPS MR/PART",106c)	DS	GateDelay	1	PrivateTag
+(0019,"PHILIPS MR/PART",106d)	DS	GateWidth	1	PrivateTag
+(0019,"PHILIPS MR/PART",106e)	DS	TriggerDelayTime	1	PrivateTag
+(0019,"PHILIPS MR/PART",1080)	IS	NumberOfChemicalShifts	1	PrivateTag
+(0019,"PHILIPS MR/PART",1081)	DS	ChemicalShift	1	PrivateTag
+(0019,"PHILIPS MR/PART",1084)	IS	NumberOfRows	1	PrivateTag
+(0019,"PHILIPS MR/PART",1085)	IS	NumberOfSamples	1	PrivateTag
+(0019,"PHILIPS MR/PART",1094)	LO	MagnetizationTransferContrast	1	PrivateTag
+(0019,"PHILIPS MR/PART",1095)	LO	SpectralPresaturationWithInversionRecovery	1	PrivateTag
+(0019,"PHILIPS MR/PART",1096)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",1097)	LO	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10a0)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10a1)	DS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10a3)	DS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10a4)	CS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10c8)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10c9)	IS	FoldoverDirectionTransverse	1	PrivateTag
+(0019,"PHILIPS MR/PART",10ca)	IS	FoldoverDirectionSagittal	1	PrivateTag
+(0019,"PHILIPS MR/PART",10cb)	IS	FoldoverDirectionCoronal	1	PrivateTag
+(0019,"PHILIPS MR/PART",10cc)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10cd)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10ce)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10cf)	IS	NumberOfEchoes	1	PrivateTag
+(0019,"PHILIPS MR/PART",10d0)	IS	ScanResolution	1	PrivateTag
+(0019,"PHILIPS MR/PART",10d2)	LO	WaterFatShift	2	PrivateTag
+(0019,"PHILIPS MR/PART",10d4)	IS	ArtifactReduction	1	PrivateTag
+(0019,"PHILIPS MR/PART",10d5)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10d6)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10d7)	DS	ScanPercentage	1	PrivateTag
+(0019,"PHILIPS MR/PART",10d8)	IS	Halfscan	1	PrivateTag
+(0019,"PHILIPS MR/PART",10d9)	IS	EPIFactor	1	PrivateTag
+(0019,"PHILIPS MR/PART",10da)	IS	TurboFactor	1	PrivateTag
+(0019,"PHILIPS MR/PART",10db)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",10e0)	IS	PercentageOfScanCompleted	1	PrivateTag
+(0019,"PHILIPS MR/PART",10e1)	IS	Unknown	1	PrivateTag
+(0019,"PHILIPS MR/PART",1100)	IS	NumberOfStacks	1	PrivateTag
+(0019,"PHILIPS MR/PART",1101)	IS	StackType	1-n	PrivateTag
+(0019,"PHILIPS MR/PART",1102)	IS	Unknown	1-n	PrivateTag
+(0019,"PHILIPS MR/PART",110b)	DS	LROffcenter	1	PrivateTag
+(0019,"PHILIPS MR/PART",110c)	DS	CCOffcenter	1	PrivateTag
+(0019,"PHILIPS MR/PART",110d)	DS	APOffcenter	1	PrivateTag
+(0019,"PHILIPS MR/PART",1145)	IS	ReconstructionResolution	1	PrivateTag
+(0019,"PHILIPS MR/PART",11fc)	IS	ResonanceFrequency	1	PrivateTag
+(0019,"PHILIPS MR/PART",12c0)	DS	TriggerDelayTimes	1	PrivateTag
+(0019,"PHILIPS MR/PART",12e0)	IS	PrepulseType	1	PrivateTag
+(0019,"PHILIPS MR/PART",12e1)	DS	PrepulseDelay	1	PrivateTag
+(0019,"PHILIPS MR/PART",12e3)	DS	PhaseContrastVelocity	1	PrivateTag
+(0021,"PHILIPS MR/PART",1000)	IS	ReconstructionNumber	1	PrivateTag
+(0021,"PHILIPS MR/PART",1010)	IS	ImageType	1	PrivateTag
+(0021,"PHILIPS MR/PART",1020)	IS	SliceNumber	1	PrivateTag
+(0021,"PHILIPS MR/PART",1030)	IS	EchoNumber	1	PrivateTag
+(0021,"PHILIPS MR/PART",1031)	DS	PatientReferenceID	1	PrivateTag
+(0021,"PHILIPS MR/PART",1035)	IS	ChemicalShiftNumber	1	PrivateTag
+(0021,"PHILIPS MR/PART",1040)	IS	PhaseNumber	1	PrivateTag
+(0021,"PHILIPS MR/PART",1050)	IS	DynamicScanNumber	1	PrivateTag
+(0021,"PHILIPS MR/PART",1060)	IS	NumberOfRowsInObject	1	PrivateTag
+(0021,"PHILIPS MR/PART",1061)	IS	RowNumber	1-n	PrivateTag
+(0021,"PHILIPS MR/PART",1062)	IS	Unknown	1-n	PrivateTag
+(0021,"PHILIPS MR/PART",1100)	DA	ScanDate	1	PrivateTag
+(0021,"PHILIPS MR/PART",1110)	TM	ScanTime	1	PrivateTag
+(0021,"PHILIPS MR/PART",1221)	IS	SliceGap	1	PrivateTag
+(0029,"PHILIPS MR/PART",00)	DS	Unknown	2	PrivateTag
+(0029,"PHILIPS MR/PART",04)	US	Unknown	1	PrivateTag
+(0029,"PHILIPS MR/PART",10)	DS	Unknown	1	PrivateTag
+(0029,"PHILIPS MR/PART",11)	DS	Unknown	1	PrivateTag
+(0029,"PHILIPS MR/PART",20)	LO	Unknown	1	PrivateTag
+(0029,"PHILIPS MR/PART",31)	DS	Unknown	2	PrivateTag
+(0029,"PHILIPS MR/PART",32)	DS	Unknown	2	PrivateTag
+(0029,"PHILIPS MR/PART",c3)	IS	ScanResolution	1	PrivateTag
+(0029,"PHILIPS MR/PART",c4)	IS	FieldOfView	1	PrivateTag
+(0029,"PHILIPS MR/PART",d5)	LT	SliceThickness	1	PrivateTag
+
+(0019,"PHILIPS-MR-1",11)	IS	ChemicalShiftNumber	1	PrivateTag
+(0019,"PHILIPS-MR-1",12)	IS	PhaseNumber	1	PrivateTag
+(0021,"PHILIPS-MR-1",01)	IS	ReconstructionNumber	1	PrivateTag
+(0021,"PHILIPS-MR-1",02)	IS	SliceNumber	1	PrivateTag
+
+(7001,"Picker NM Private Group",01)	UI	Unknown	1	PrivateTag
+(7001,"Picker NM Private Group",02)	OB	Unknown	1	PrivateTag
+
+(0019,"SIEMENS CM VA0  ACQU",10)	LT	ParameterFileName	1	PrivateTag
+(0019,"SIEMENS CM VA0  ACQU",11)	LO	SequenceFileName	1	PrivateTag
+(0019,"SIEMENS CM VA0  ACQU",12)	LT	SequenceFileOwner	1	PrivateTag
+(0019,"SIEMENS CM VA0  ACQU",13)	LT	SequenceDescription	1	PrivateTag
+(0019,"SIEMENS CM VA0  ACQU",14)	LT	EPIFileName	1	PrivateTag
+
+(0009,"SIEMENS CM VA0  CMS",00)	DS	NumberOfMeasurements	1	PrivateTag
+(0009,"SIEMENS CM VA0  CMS",10)	LT	StorageMode	1	PrivateTag
+(0009,"SIEMENS CM VA0  CMS",12)	UL	EvaluationMaskImage	1	PrivateTag
+(0009,"SIEMENS CM VA0  CMS",26)	DA	LastMoveDate	1	PrivateTag
+(0009,"SIEMENS CM VA0  CMS",27)	TM	LastMoveTime	1	PrivateTag
+(0011,"SIEMENS CM VA0  CMS",0a)	LT	Unknown	1	PrivateTag
+(0011,"SIEMENS CM VA0  CMS",10)	DA	RegistrationDate	1	PrivateTag
+(0011,"SIEMENS CM VA0  CMS",11)	TM	RegistrationTime	1	PrivateTag
+(0011,"SIEMENS CM VA0  CMS",22)	LT	Unknown	1	PrivateTag
+(0011,"SIEMENS CM VA0  CMS",23)	DS	UsedPatientWeight	1	PrivateTag
+(0011,"SIEMENS CM VA0  CMS",40)	IS	OrganCode	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",00)	LT	ModifyingPhysician	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",10)	DA	ModificationDate	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",12)	TM	ModificationTime	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",20)	LO	PatientName	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",22)	LO	PatientId	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",30)	DA	PatientBirthdate	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",31)	DS	PatientWeight	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",32)	LT	PatientsMaidenName	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",33)	LT	ReferringPhysician	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",34)	LT	AdmittingDiagnosis	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",35)	LO	PatientSex	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",40)	LO	ProcedureDescription	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",42)	LO	RestDirection	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",44)	LO	PatientPosition	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",46)	LT	ViewDirection	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",50)	LT	Unknown	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",51)	LT	Unknown	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",52)	LT	Unknown	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",53)	LT	Unknown	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",54)	LT	Unknown	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",55)	LT	Unknown	1	PrivateTag
+(0013,"SIEMENS CM VA0  CMS",56)	LT	Unknown	1	PrivateTag
+(0019,"SIEMENS CM VA0  CMS",10)	DS	NetFrequency	1	PrivateTag
+(0019,"SIEMENS CM VA0  CMS",20)	LT	MeasurementMode	1	PrivateTag
+(0019,"SIEMENS CM VA0  CMS",30)	LT	CalculationMode	1	PrivateTag
+(0019,"SIEMENS CM VA0  CMS",50)	IS	NoiseLevel	1	PrivateTag
+(0019,"SIEMENS CM VA0  CMS",60)	IS	NumberOfDataBytes	1	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",20)	DS	FoV	2	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",22)	DS	ImageMagnificationFactor	1	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",24)	DS	ImageScrollOffset	2	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",26)	IS	ImagePixelOffset	1	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",30)	LT	ViewDirection	1	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",32)	CS	PatientRestDirection	1	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",60)	DS	ImagePosition	3	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",61)	DS	ImageNormal	3	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",63)	DS	ImageDistance	1	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",65)	US	ImagePositioningHistoryMask	1	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",6a)	DS	ImageRow	3	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",6b)	DS	ImageColumn	3	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",70)	LT	PatientOrientationSet1	3	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",71)	LT	PatientOrientationSet2	3	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",80)	LT	StudyName	1	PrivateTag
+(0021,"SIEMENS CM VA0  CMS",82)	LT	StudyType	3	PrivateTag
+(0029,"SIEMENS CM VA0  CMS",10)	LT	WindowStyle	1	PrivateTag
+(0029,"SIEMENS CM VA0  CMS",11)	LT	Unknown	1	PrivateTag
+(0029,"SIEMENS CM VA0  CMS",13)	LT	Unknown	1	PrivateTag
+(0029,"SIEMENS CM VA0  CMS",20)	LT	PixelQualityCode	3	PrivateTag
+(0029,"SIEMENS CM VA0  CMS",22)	IS	PixelQualityValue	3	PrivateTag
+(0029,"SIEMENS CM VA0  CMS",50)	LT	ArchiveCode	1	PrivateTag
+(0029,"SIEMENS CM VA0  CMS",51)	LT	ExposureCode	1	PrivateTag
+(0029,"SIEMENS CM VA0  CMS",52)	LT	SortCode	1	PrivateTag
+(0029,"SIEMENS CM VA0  CMS",53)	LT	Unknown	1	PrivateTag
+(0029,"SIEMENS CM VA0  CMS",60)	LT	Splash	1	PrivateTag
+(0051,"SIEMENS CM VA0  CMS",10)	LT	ImageText	1-n	PrivateTag
+(6021,"SIEMENS CM VA0  CMS",00)	LT	ImageGraphicsFormatCode	1	PrivateTag
+(6021,"SIEMENS CM VA0  CMS",10)	LT	ImageGraphics	1	PrivateTag
+(7fe1,"SIEMENS CM VA0  CMS",00)	OB	BinaryData	1-n	PrivateTag
+
+(0009,"SIEMENS CM VA0  LAB",10)	LT	GeneratorIdentificationLabel	1	PrivateTag
+(0009,"SIEMENS CM VA0  LAB",11)	LT	GantryIdentificationLabel	1	PrivateTag
+(0009,"SIEMENS CM VA0  LAB",12)	LT	X-RayTubeIdentificationLabel	1	PrivateTag
+(0009,"SIEMENS CM VA0  LAB",13)	LT	DetectorIdentificationLabel	1	PrivateTag
+(0009,"SIEMENS CM VA0  LAB",14)	LT	DASIdentificationLabel	1	PrivateTag
+(0009,"SIEMENS CM VA0  LAB",15)	LT	SMIIdentificationLabel	1	PrivateTag
+(0009,"SIEMENS CM VA0  LAB",16)	LT	CPUIdentificationLabel	1	PrivateTag
+(0009,"SIEMENS CM VA0  LAB",20)	LT	HeaderVersion	1	PrivateTag
+
+(0029,"SIEMENS CSA HEADER",08)	CS	CSAImageHeaderType	1	PrivateTag
+(0029,"SIEMENS CSA HEADER",09)	LO	CSAImageHeaderVersion	1	PrivateTag
+(0029,"SIEMENS CSA HEADER",10)	OB	CSAImageHeaderInfo	1	PrivateTag
+(0029,"SIEMENS CSA HEADER",18)	CS	CSASeriesHeaderType	1	PrivateTag
+(0029,"SIEMENS CSA HEADER",19)	LO	CSASeriesHeaderVersion	1	PrivateTag
+(0029,"SIEMENS CSA HEADER",20)	OB	CSASeriesHeaderInfo	1	PrivateTag
+
+(0029,"SIEMENS CSA NON-IMAGE",08)	CS	CSADataType	1	PrivateTag
+(0029,"SIEMENS CSA NON-IMAGE",09)	LO	CSADataVersion	1	PrivateTag
+(0029,"SIEMENS CSA NON-IMAGE",10)	OB	CSADataInfo	1	PrivateTag
+(7FE1,"SIEMENS CSA NON-IMAGE",10)	OB	CSAData	1	PrivateTag
+
+(0019,"SIEMENS CT VA0  COAD",10)	DS	DistanceSourceToSourceSideCollimator	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",11)	DS	DistanceSourceToDetectorSideCollimator	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",20)	IS	NumberOfPossibleChannels	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",21)	IS	MeanChannelNumber	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",22)	DS	DetectorSpacing	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",23)	DS	DetectorCenter	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",24)	DS	ReadingIntegrationTime	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",50)	DS	DetectorAlignment	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",52)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",54)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",60)	DS	FocusAlignment	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",65)	UL	FocalSpotDeflectionAmplitude	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",66)	UL	FocalSpotDeflectionPhase	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",67)	UL	FocalSpotDeflectionOffset	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",70)	DS	WaterScalingFactor	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",71)	DS	InterpolationFactor	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",80)	LT	PatientRegion	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",82)	LT	PatientPhaseOfLife	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",90)	DS	OsteoOffset	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",92)	DS	OsteoRegressionLineSlope	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",93)	DS	OsteoRegressionLineIntercept	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",94)	DS	OsteoStandardizationCode	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",96)	IS	OsteoPhantomNumber	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",A3)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",A4)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",A5)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",A6)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",A7)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",A8)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",A9)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",AA)	LT	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",AB)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",AC)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",AD)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",AE)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",AF)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",B0)	DS	FeedPerRotation	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",BD)	IS	PulmoTriggerLevel	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",BE)	DS	ExpiratoricReserveVolume	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",BF)	DS	VitalCapacity	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",C0)	DS	PulmoWater	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",C1)	DS	PulmoAir	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",C2)	DA	PulmoDate	1	PrivateTag
+(0019,"SIEMENS CT VA0  COAD",C3)	TM	PulmoTime	1	PrivateTag
+
+(0019,"SIEMENS CT VA0  GEN",10)	DS	SourceSideCollimatorAperture	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",11)	DS	DetectorSideCollimatorAperture	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",20)	DS	ExposureTime	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",21)	DS	ExposureCurrent	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",25)	DS	KVPGeneratorPowerCurrent	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",26)	DS	GeneratorVoltage	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",40)	UL	MasterControlMask	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",42)	US	ProcessingMask	5	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",44)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",45)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",62)	IS	NumberOfVirtuellChannels	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",70)	IS	NumberOfReadings	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",71)	LT	Unknown	1-n	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",74)	IS	NumberOfProjections	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",75)	IS	NumberOfBytes	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",80)	LT	ReconstructionAlgorithmSet	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",81)	LT	ReconstructionAlgorithmIndex	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",82)	LT	RegenerationSoftwareVersion	1	PrivateTag
+(0019,"SIEMENS CT VA0  GEN",88)	DS	Unknown	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",10)	IS	RotationAngle	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",11)	IS	StartAngle	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",20)	US	Unknown	1-n	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",30)	IS	TopogramTubePosition	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",32)	DS	LengthOfTopogram	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",34)	DS	TopogramCorrectionFactor	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",36)	DS	MaximumTablePosition	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",40)	IS	TableMoveDirectionCode	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",45)	IS	VOIStartRow	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",46)	IS	VOIStopRow	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",47)	IS	VOIStartColumn	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",48)	IS	VOIStopColumn	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",49)	IS	VOIStartSlice	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",4a)	IS	VOIStopSlice	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",50)	IS	VectorStartRow	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",51)	IS	VectorRowStep	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",52)	IS	VectorStartColumn	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",53)	IS	VectorColumnStep	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",60)	IS	RangeTypeCode	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",62)	IS	ReferenceTypeCode	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",70)	DS	ObjectOrientation	3	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",72)	DS	LightOrientation	3	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",75)	DS	LightBrightness	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",76)	DS	LightContrast	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",7a)	IS	OverlayThreshold	2	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",7b)	IS	SurfaceThreshold	2	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",7c)	IS	GreyScaleThreshold	2	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",a0)	DS	Unknown	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",a2)	LT	Unknown	1	PrivateTag
+(0021,"SIEMENS CT VA0  GEN",a7)	LT	Unknown	1	PrivateTag
+
+(0009,"SIEMENS CT VA0  IDE",10)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS CT VA0  IDE",30)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS CT VA0  IDE",31)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS CT VA0  IDE",32)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS CT VA0  IDE",34)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS CT VA0  IDE",40)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS CT VA0  IDE",42)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS CT VA0  IDE",50)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS CT VA0  IDE",51)	LT	Unknown	1	PrivateTag
+
+(0009,"SIEMENS CT VA0  ORI",20)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS CT VA0  ORI",30)	LT	Unknown	1	PrivateTag
+
+(6021,"SIEMENS CT VA0  OST",00)	LT	OsteoContourComment	1	PrivateTag
+(6021,"SIEMENS CT VA0  OST",10)	US	OsteoContourBuffer	256	PrivateTag
+
+(0021,"SIEMENS CT VA0  RAW",10)	UL	CreationMask	2	PrivateTag
+(0021,"SIEMENS CT VA0  RAW",20)	UL	EvaluationMask	2	PrivateTag
+(0021,"SIEMENS CT VA0  RAW",30)	US	ExtendedProcessingMask	7	PrivateTag
+(0021,"SIEMENS CT VA0  RAW",40)	US	Unknown	1-n	PrivateTag
+(0021,"SIEMENS CT VA0  RAW",41)	US	Unknown	1-n	PrivateTag
+(0021,"SIEMENS CT VA0  RAW",42)	US	Unknown	1-n	PrivateTag
+(0021,"SIEMENS CT VA0  RAW",43)	US	Unknown	1-n	PrivateTag
+(0021,"SIEMENS CT VA0  RAW",44)	US	Unknown	1-n	PrivateTag
+(0021,"SIEMENS CT VA0  RAW",50)	LT	Unknown	1	PrivateTag
+
+(0009,"SIEMENS DICOM",10)	UN	Unknown	1	PrivateTag
+(0009,"SIEMENS DICOM",12)	LT	Unknown	1	PrivateTag
+
+(0019,"SIEMENS DLR.01",10)	LT	MeasurementMode	1	PrivateTag
+(0019,"SIEMENS DLR.01",11)	LT	ImageType	1	PrivateTag
+(0019,"SIEMENS DLR.01",15)	LT	SoftwareVersion	1	PrivateTag
+(0019,"SIEMENS DLR.01",20)	LT	MPMCode	1	PrivateTag
+(0019,"SIEMENS DLR.01",21)	LT	Latitude	1	PrivateTag
+(0019,"SIEMENS DLR.01",22)	LT	Sensitivity	1	PrivateTag
+(0019,"SIEMENS DLR.01",23)	LT	EDR	1	PrivateTag
+(0019,"SIEMENS DLR.01",24)	LT	LFix	1	PrivateTag
+(0019,"SIEMENS DLR.01",25)	LT	SFix	1	PrivateTag
+(0019,"SIEMENS DLR.01",26)	LT	PresetMode	1	PrivateTag
+(0019,"SIEMENS DLR.01",27)	LT	Region	1	PrivateTag
+(0019,"SIEMENS DLR.01",28)	LT	Subregion	1	PrivateTag
+(0019,"SIEMENS DLR.01",30)	LT	Orientation	1	PrivateTag
+(0019,"SIEMENS DLR.01",31)	LT	MarkOnFilm	1	PrivateTag
+(0019,"SIEMENS DLR.01",32)	LT	RotationOnDRC	1	PrivateTag
+(0019,"SIEMENS DLR.01",40)	LT	ReaderType	1	PrivateTag
+(0019,"SIEMENS DLR.01",41)	LT	SubModality	1	PrivateTag
+(0019,"SIEMENS DLR.01",42)	LT	ReaderSerialNumber	1	PrivateTag
+(0019,"SIEMENS DLR.01",50)	LT	CassetteScale	1	PrivateTag
+(0019,"SIEMENS DLR.01",51)	LT	CassetteMatrix	1	PrivateTag
+(0019,"SIEMENS DLR.01",52)	LT	CassetteSubmatrix	1	PrivateTag
+(0019,"SIEMENS DLR.01",53)	LT	Barcode	1	PrivateTag
+(0019,"SIEMENS DLR.01",60)	LT	ContrastType	1	PrivateTag
+(0019,"SIEMENS DLR.01",61)	LT	RotationAmount	1	PrivateTag
+(0019,"SIEMENS DLR.01",62)	LT	RotationCenter	1	PrivateTag
+(0019,"SIEMENS DLR.01",63)	LT	DensityShift	1	PrivateTag
+(0019,"SIEMENS DLR.01",64)	US	FrequencyRank	1	PrivateTag
+(0019,"SIEMENS DLR.01",65)	LT	FrequencyEnhancement	1	PrivateTag
+(0019,"SIEMENS DLR.01",66)	LT	FrequencyType	1	PrivateTag
+(0019,"SIEMENS DLR.01",67)	LT	KernelLength	1	PrivateTag
+(0019,"SIEMENS DLR.01",68)	UL	KernelMode	1	PrivateTag
+(0019,"SIEMENS DLR.01",69)	UL	ConvolutionMode	1	PrivateTag
+(0019,"SIEMENS DLR.01",70)	LT	PLASource	1	PrivateTag
+(0019,"SIEMENS DLR.01",71)	LT	PLADestination	1	PrivateTag
+(0019,"SIEMENS DLR.01",75)	LT	UIDOriginalImage	1	PrivateTag
+(0019,"SIEMENS DLR.01",76)	LT	Unknown	1	PrivateTag
+(0019,"SIEMENS DLR.01",80)	LT	ReaderHeader	1	PrivateTag
+(0019,"SIEMENS DLR.01",90)	LT	PLAOfSecondaryDestination	1	PrivateTag
+(0019,"SIEMENS DLR.01",a0)	DS	Unknown	1	PrivateTag
+(0019,"SIEMENS DLR.01",a1)	DS	Unknown	1	PrivateTag
+(0041,"SIEMENS DLR.01",10)	US	NumberOfHardcopies	1	PrivateTag
+(0041,"SIEMENS DLR.01",20)	LT	FilmFormat	1	PrivateTag
+(0041,"SIEMENS DLR.01",30)	LT	FilmSize	1	PrivateTag
+(0041,"SIEMENS DLR.01",31)	LT	FullFilmFormat	1	PrivateTag
+
+(0003,"SIEMENS ISI",08)	US	ISICommandField	1	PrivateTag
+(0003,"SIEMENS ISI",11)	US	AttachIDApplicationCode	1	PrivateTag
+(0003,"SIEMENS ISI",12)	UL	AttachIDMessageCount	1	PrivateTag
+(0003,"SIEMENS ISI",13)	DA	AttachIDDate	1	PrivateTag
+(0003,"SIEMENS ISI",14)	TM	AttachIDTime	1	PrivateTag
+(0003,"SIEMENS ISI",20)	US	MessageType	1	PrivateTag
+(0003,"SIEMENS ISI",30)	DA	MaxWaitingDate	1	PrivateTag
+(0003,"SIEMENS ISI",31)	TM	MaxWaitingTime	1	PrivateTag
+(0009,"SIEMENS ISI",01)	UN	RISPatientInfoIMGEF	1	PrivateTag
+(0011,"SIEMENS ISI",03)	LT	PatientUID	1	PrivateTag
+(0011,"SIEMENS ISI",04)	LT	PatientID	1	PrivateTag
+(0011,"SIEMENS ISI",0a)	LT	CaseID	1	PrivateTag
+(0011,"SIEMENS ISI",22)	LT	RequestID	1	PrivateTag
+(0011,"SIEMENS ISI",23)	LT	ExaminationUID	1	PrivateTag
+(0011,"SIEMENS ISI",a1)	DA	PatientRegistrationDate	1	PrivateTag
+(0011,"SIEMENS ISI",a2)	TM	PatientRegistrationTime	1	PrivateTag
+(0011,"SIEMENS ISI",b0)	LT	PatientLastName	1	PrivateTag
+(0011,"SIEMENS ISI",b2)	LT	PatientFirstName	1	PrivateTag
+(0011,"SIEMENS ISI",b4)	LT	PatientHospitalStatus	1	PrivateTag
+(0011,"SIEMENS ISI",bc)	TM	CurrentLocationTime	1	PrivateTag
+(0011,"SIEMENS ISI",c0)	LT	PatientInsuranceStatus	1	PrivateTag
+(0011,"SIEMENS ISI",d0)	LT	PatientBillingType	1	PrivateTag
+(0011,"SIEMENS ISI",d2)	LT	PatientBillingAddress	1	PrivateTag
+(0031,"SIEMENS ISI",12)	LT	ExaminationReason	1	PrivateTag
+(0031,"SIEMENS ISI",30)	DA	RequestedDate	1	PrivateTag
+(0031,"SIEMENS ISI",32)	TM	WorklistRequestStartTime	1	PrivateTag
+(0031,"SIEMENS ISI",33)	TM	WorklistRequestEndTime	1	PrivateTag
+(0031,"SIEMENS ISI",4a)	TM	RequestedTime	1	PrivateTag
+(0031,"SIEMENS ISI",80)	LT	RequestedLocation	1	PrivateTag
+(0055,"SIEMENS ISI",46)	LT	CurrentWard	1	PrivateTag
+(0193,"SIEMENS ISI",02)	DS	RISKey	1	PrivateTag
+(0307,"SIEMENS ISI",01)	UN	RISWorklistIMGEF	1	PrivateTag
+(0309,"SIEMENS ISI",01)	UN	RISReportIMGEF	1	PrivateTag
+(4009,"SIEMENS ISI",01)	LT	ReportID	1	PrivateTag
+(4009,"SIEMENS ISI",20)	LT	ReportStatus	1	PrivateTag
+(4009,"SIEMENS ISI",30)	DA	ReportCreationDate	1	PrivateTag
+(4009,"SIEMENS ISI",70)	LT	ReportApprovingPhysician	1	PrivateTag
+(4009,"SIEMENS ISI",e0)	LT	ReportText	1	PrivateTag
+(4009,"SIEMENS ISI",e1)	LT	ReportAuthor	1	PrivateTag
+(4009,"SIEMENS ISI",e3)	LT	ReportingRadiologist	1	PrivateTag
+
+(0029,"SIEMENS MED DISPLAY",04)	LT	PhotometricInterpretation	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",10)	US	RowsOfSubmatrix	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",11)	US	ColumnsOfSubmatrix	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",20)	US	Unknown	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",21)	US	Unknown	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",50)	US	OriginOfSubmatrix	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",99)	LT	ShutterType	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",a0)	US	RowsOfRectangularShutter	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",a1)	US	ColumnsOfRectangularShutter	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",a2)	US	OriginOfRectangularShutter	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",b0)	US	RadiusOfCircularShutter	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",b2)	US	OriginOfCircularShutter	1	PrivateTag
+(0029,"SIEMENS MED DISPLAY",c1)	US	ContourOfIrregularShutter	1	PrivateTag
+
+(0029,"SIEMENS MED HG",10)	US	ListOfGroupNumbers	1	PrivateTag
+(0029,"SIEMENS MED HG",15)	LT	ListOfShadowOwnerCodes	1	PrivateTag
+(0029,"SIEMENS MED HG",20)	US	ListOfElementNumbers	1	PrivateTag
+(0029,"SIEMENS MED HG",30)	US	ListOfTotalDisplayLength	1	PrivateTag
+(0029,"SIEMENS MED HG",40)	LT	ListOfDisplayPrefix	1	PrivateTag
+(0029,"SIEMENS MED HG",50)	LT	ListOfDisplayPostfix	1	PrivateTag
+(0029,"SIEMENS MED HG",60)	US	ListOfTextPosition	1	PrivateTag
+(0029,"SIEMENS MED HG",70)	LT	ListOfTextConcatenation	1	PrivateTag
+(0029,"SIEMENS MED MG",10)	US	ListOfGroupNumbers	1	PrivateTag
+(0029,"SIEMENS MED MG",15)	LT	ListOfShadowOwnerCodes	1	PrivateTag
+(0029,"SIEMENS MED MG",20)	US	ListOfElementNumbers	1	PrivateTag
+(0029,"SIEMENS MED MG",30)	US	ListOfTotalDisplayLength	1	PrivateTag
+(0029,"SIEMENS MED MG",40)	LT	ListOfDisplayPrefix	1	PrivateTag
+(0029,"SIEMENS MED MG",50)	LT	ListOfDisplayPostfix	1	PrivateTag
+(0029,"SIEMENS MED MG",60)	US	ListOfTextPosition	1	PrivateTag
+(0029,"SIEMENS MED MG",70)	LT	ListOfTextConcatenation	1	PrivateTag
+
+(0009,"SIEMENS MED",10)	LO	RecognitionCode	1	PrivateTag
+(0009,"SIEMENS MED",30)	UL	ByteOffsetOfOriginalHeader	1	PrivateTag
+(0009,"SIEMENS MED",31)	UL	LengthOfOriginalHeader	1	PrivateTag
+(0009,"SIEMENS MED",40)	UL	ByteOffsetOfPixelmatrix	1	PrivateTag
+(0009,"SIEMENS MED",41)	UL	LengthOfPixelmatrixInBytes	1	PrivateTag
+(0009,"SIEMENS MED",50)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS MED",51)	LT	Unknown	1	PrivateTag
+(0009,"SIEMENS MED",f5)	LT	PDMEFIDPlaceholder	1	PrivateTag
+(0009,"SIEMENS MED",f6)	LT	PDMDataObjectTypeExtension	1	PrivateTag
+(0021,"SIEMENS MED",10)	DS	Zoom	1	PrivateTag
+(0021,"SIEMENS MED",11)	DS	Target	2	PrivateTag
+(0021,"SIEMENS MED",12)	IS	TubeAngle	1	PrivateTag
+(0021,"SIEMENS MED",20)	US	ROIMask	1	PrivateTag
+(7001,"SIEMENS MED",10)	LT	Dummy	1	PrivateTag
+(7003,"SIEMENS MED",10)	LT	Header	1	PrivateTag
+(7005,"SIEMENS MED",10)	LT	Dummy	1	PrivateTag
+
+(0029,"SIEMENS MEDCOM HEADER",08)	CS	MedComHeaderType	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",09)	LO	MedComHeaderVersion	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",10)	OB	MedComHeaderInfo	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",20)	OB	MedComHistoryInformation	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",31)	LO	PMTFInformation1	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",32)	UL	PMTFInformation2	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",33)	UL	PMTFInformation3	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",34)	CS	PMTFInformation4	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",35)	UL	PMTFInformation5	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",40)	SQ	ApplicationHeaderSequence	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",41)	CS	ApplicationHeaderType	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",42)	LO	ApplicationHeaderID	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",43)	LO	ApplicationHeaderVersion	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",44)	OB	ApplicationHeaderInfo	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",50)	LO	WorkflowControlFlags	8	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",51)	CS	ArchiveManagementFlagKeepOnline	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",52)	CS	ArchiveManagementFlagDoNotArchive	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",53)	CS	ImageLocationStatus	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",54)	DS	EstimatedRetrieveTime	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",55)	DS	DataSizeOfRetrievedImages	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",70)	SQ	SiemensLinkSequence	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",71)	AT	ReferencedTag	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",72)	CS	ReferencedTagType	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",73)	UL	ReferencedValueLength	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",74)	CS	ReferencedObjectDeviceType	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",75)	OB	ReferencedObjectDeviceLocation	1	PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",76)	OB	ReferencedObjectDeviceID	1	PrivateTag
+
+(0029,"SIEMENS MEDCOM HEADER2",60)	LO	SeriesWorkflowStatus	1	PrivateTag
+
+(0029,"SIEMENS MEDCOM OOG",08)	CS	MEDCOMOOGType	1	PrivateTag
+(0029,"SIEMENS MEDCOM OOG",09)	LO	MEDCOMOOGVersion	1	PrivateTag
+(0029,"SIEMENS MEDCOM OOG",10)	OB	MEDCOMOOGInfo	1	PrivateTag
+
+(0019,"SIEMENS MR VA0  COAD",12)	DS	MagneticFieldStrength	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",14)	DS	ADCVoltage	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",16)	DS	ADCOffset	2	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",20)	DS	TransmitterAmplitude	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",21)	IS	NumberOfTransmitterAmplitudes	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",22)	DS	TransmitterAttenuator	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",24)	DS	TransmitterCalibration	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",26)	DS	TransmitterReference	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",50)	DS	ReceiverTotalGain	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",51)	DS	ReceiverAmplifierGain	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",52)	DS	ReceiverPreamplifierGain	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",54)	DS	ReceiverCableAttenuation	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",55)	DS	ReceiverReferenceGain	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",56)	DS	ReceiverFilterFrequency	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",60)	DS	ReconstructionScaleFactor	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",62)	DS	ReferenceScaleFactor	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",70)	DS	PhaseGradientAmplitude	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",71)	DS	ReadoutGradientAmplitude	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",72)	DS	SelectionGradientAmplitude	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",80)	DS	GradientDelayTime	3	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",82)	DS	TotalGradientDelayTime	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",90)	LT	SensitivityCorrectionLabel	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",91)	DS	SaturationPhaseEncodingVectorCoronalComponent	6	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",92)	DS	SaturationReadoutVectorCoronalComponent	6	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",a0)	US	RFWatchdogMask	3	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",a1)	DS	EPIReconstructionSlope	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",a2)	DS	RFPowerErrorIndicator	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",a5)	DS	SpecificAbsorptionRateWholeBody	3	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",a6)	DS	SpecificEnergyDose	3	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",b0)	UL	AdjustmentStatusMask	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",c1)	DS	EPICapacity	6	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",c2)	DS	EPIInductance	3	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",c3)	IS	EPISwitchConfigurationCode	1-n	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",c4)	IS	EPISwitchHardwareCode	1-n	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",c5)	DS	EPISwitchDelayTime	1-n	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",d1)	DS	FlowSensitivity	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",d2)	LT	CalculationSubmode	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",d3)	DS	FieldOfViewRatio	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",d4)	IS	BaseRawMatrixSize	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",d5)	IS	2DOversamplingLines	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",d6)	IS	3DPhaseOversamplingPartitions	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",d7)	IS	EchoLinePosition	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",d8)	IS	EchoColumnPosition	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",d9)	IS	LinesPerSegment	1	PrivateTag
+(0019,"SIEMENS MR VA0  COAD",da)	LT	PhaseCodingDirection	1	PrivateTag
+
+(0019,"SIEMENS MR VA0  GEN",10)	DS	TotalMeasurementTimeNominal	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",11)	DS	TotalMeasurementTimeCurrent	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",12)	DS	StartDelayTime	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",13)	DS	DwellTime	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",14)	IS	NumberOfPhases	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",16)	UL	SequenceControlMask	2	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",18)	UL	MeasurementStatusMask	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",20)	IS	NumberOfFourierLinesNominal	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",21)	IS	NumberOfFourierLinesCurrent	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",26)	IS	NumberOfFourierLinesAfterZero	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",28)	IS	FirstMeasuredFourierLine	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",30)	IS	AcquisitionColumns	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",31)	IS	ReconstructionColumns	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",40)	IS	ArrayCoilElementNumber	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",41)	UL	ArrayCoilElementSelectMask	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",42)	UL	ArrayCoilElementDataMask	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",43)	IS	ArrayCoilElementToADCConnect	1-n	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",44)	DS	ArrayCoilElementNoiseLevel	1-n	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",45)	IS	ArrayCoilADCPairNumber	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",46)	UL	ArrayCoilCombinationMask	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",50)	IS	NumberOfAverages	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",60)	DS	FlipAngle	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",70)	IS	NumberOfPrescans	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",81)	LT	FilterTypeForRawData	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",82)	DS	FilterParameterForRawData	1-n	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",83)	LT	FilterTypeForImageData	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",84)	DS	FilterParameterForImageData	1-n	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",85)	LT	FilterTypeForPhaseCorrection	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",86)	DS	FilterParameterForPhaseCorrection	1-n	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",87)	LT	NormalizationFilterTypeForImageData	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",88)	DS	NormalizationFilterParameterForImageData	1-n	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",90)	IS	NumberOfSaturationRegions	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",91)	DS	SaturationPhaseEncodingVectorSagittalComponent	6	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",92)	DS	SaturationReadoutVectorSagittalComponent	6	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",93)	DS	EPIStimulationMonitorMode	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",94)	DS	ImageRotationAngle	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",96)	UL	CoilIDMask	3	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",97)	UL	CoilClassMask	2	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",98)	DS	CoilPosition	3	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",a0)	DS	EPIReconstructionPhase	1	PrivateTag
+(0019,"SIEMENS MR VA0  GEN",a1)	DS	EPIReconstructionSlope	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",20)	IS	PhaseCorrectionRowsSequence	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",21)	IS	PhaseCorrectionColumnsSequence	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",22)	IS	PhaseCorrectionRowsReconstruction	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",24)	IS	PhaseCorrectionColumnsReconstruction	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",30)	IS	NumberOf3DRawPartitionsNominal	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",31)	IS	NumberOf3DRawPartitionsCurrent	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",34)	IS	NumberOf3DImagePartitions	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",36)	IS	Actual3DImagePartitionNumber	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",39)	DS	SlabThickness	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",40)	IS	NumberOfSlicesNominal	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",41)	IS	NumberOfSlicesCurrent	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",42)	IS	CurrentSliceNumber	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",43)	IS	CurrentGroupNumber	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",44)	DS	CurrentSliceDistanceFactor	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",45)	IS	MIPStartRow	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",46)	IS	MIPStopRow	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",47)	IS	MIPStartColumn	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",48)	IS	MIPStartColumn	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",49)	IS	MIPStartSlice Name=	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",4a)	IS	MIPStartSlice	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",4f)	LT	OrderofSlices	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",50)	US	SignalMask	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",52)	DS	DelayAfterTrigger	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",53)	IS	RRInterval	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",54)	DS	NumberOfTriggerPulses	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",56)	DS	RepetitionTimeEffective	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",57)	LT	GatePhase	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",58)	DS	GateThreshold	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",59)	DS	GatedRatio	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",60)	IS	NumberOfInterpolatedImages	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",70)	IS	NumberOfEchoes	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",72)	DS	SecondEchoTime	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",73)	DS	SecondRepetitionTime	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",80)	IS	CardiacCode	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",91)	DS	SaturationPhaseEncodingVectorTransverseComponent	6	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",92)	DS	SaturationReadoutVectorTransverseComponent	6	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",93)	DS	EPIChangeValueOfMagnitude	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",94)	DS	EPIChangeValueOfXComponent	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",95)	DS	EPIChangeValueOfYComponent	1	PrivateTag
+(0021,"SIEMENS MR VA0  GEN",96)	DS	EPIChangeValueOfZComponent	1	PrivateTag
+
+(0021,"SIEMENS MR VA0  RAW",00)	LT	SequenceType	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",01)	IS	VectorSizeOriginal	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",02)	IS	VectorSizeExtended	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",03)	DS	AcquiredSpectralRange	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",04)	DS	VOIPosition	3	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",05)	DS	VOISize	3	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",06)	IS	CSIMatrixSizeOriginal	3	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",07)	IS	CSIMatrixSizeExtended	3	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",08)	DS	SpatialGridShift	3	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",09)	DS	SignalLimitsMinimum	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",10)	DS	SignalLimitsMaximum	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",11)	DS	SpecInfoMask	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",12)	DS	EPITimeRateOfChangeOfMagnitude	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",13)	DS	EPITimeRateOfChangeOfXComponent	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",14)	DS	EPITimeRateOfChangeOfYComponent	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",15)	DS	EPITimeRateOfChangeOfZComponent	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",16)	DS	EPITimeRateOfChangeLegalLimit1	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",17)	DS	EPIOperationModeFlag	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",18)	DS	EPIFieldCalculationSafetyFactor	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",19)	DS	EPILegalLimit1OfChangeValue	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",20)	DS	EPILegalLimit2OfChangeValue	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",21)	DS	EPIRiseTime	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",30)	DS	ArrayCoilADCOffset	16	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",31)	DS	ArrayCoilPreamplifierGain	16	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",50)	LT	SaturationType	1	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",51)	DS	SaturationNormalVector	3	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",52)	DS	SaturationPositionVector	3	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",53)	DS	SaturationThickness	6	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",54)	DS	SaturationWidth	6	PrivateTag
+(0021,"SIEMENS MR VA0  RAW",55)	DS	SaturationDistance	6	PrivateTag
+
+(7fe3,"SIEMENS NUMARIS II",00)	LT	ImageGraphicsFormatCode	1	PrivateTag
+(7fe3,"SIEMENS NUMARIS II",10)	OB	ImageGraphics	1	PrivateTag
+(7fe3,"SIEMENS NUMARIS II",20)	OB	ImageGraphicsDummy	1	PrivateTag
+
+(0011,"SIEMENS RA GEN",20)	SL	FluoroTimer	1	PrivateTag
+(0011,"SIEMENS RA GEN",25)	SL	PtopDoseAreaProduct	1	PrivateTag
+(0011,"SIEMENS RA GEN",26)	SL	PtopTotalSkinDose	1	PrivateTag
+(0011,"SIEMENS RA GEN",30)	LT	Unknown	1	PrivateTag
+(0011,"SIEMENS RA GEN",35)	LO	PatientInitialPuckCounter	1	PrivateTag
+(0011,"SIEMENS RA GEN",40)	SS	SPIDataObjectType	1	PrivateTag
+(0019,"SIEMENS RA GEN",15)	LO	AcquiredPlane	1	PrivateTag
+(0019,"SIEMENS RA GEN",1f)	SS	DefaultTableIsoCenterHeight	1	PrivateTag
+(0019,"SIEMENS RA GEN",20)	SL	SceneFlag	1	PrivateTag
+(0019,"SIEMENS RA GEN",22)	SL	RefPhotofileFlag	1	PrivateTag
+(0019,"SIEMENS RA GEN",24)	LO	SceneName	1	PrivateTag
+(0019,"SIEMENS RA GEN",26)	SS	AcquisitionIndex	1	PrivateTag
+(0019,"SIEMENS RA GEN",28)	SS	MixedPulseMode	1	PrivateTag
+(0019,"SIEMENS RA GEN",2a)	SS	NoOfPositions	1	PrivateTag
+(0019,"SIEMENS RA GEN",2c)	SS	NoOfPhases	1	PrivateTag
+(0019,"SIEMENS RA GEN",2e)	SS	FrameRateForPositions	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",30)	SS	NoOfFramesForPositions	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",32)	SS	SteppingDirection	1	PrivateTag
+(0019,"SIEMENS RA GEN",34)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",36)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",38)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",3a)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",3c)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",3e)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",40)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",42)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",44)	SS	ImageTransferDelay	1	PrivateTag
+(0019,"SIEMENS RA GEN",46)	SL	InversFlag	1	PrivateTag
+(0019,"SIEMENS RA GEN",48)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",4a)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",4c)	SS	BlankingCircleDiameter	1	PrivateTag
+(0019,"SIEMENS RA GEN",50)	SL	StandDataValid	1	PrivateTag
+(0019,"SIEMENS RA GEN",52)	SS	TableTilt	1	PrivateTag
+(0019,"SIEMENS RA GEN",54)	SS	TableAxisRotation	1	PrivateTag
+(0019,"SIEMENS RA GEN",56)	SS	TableLongitudalPosition	1	PrivateTag
+(0019,"SIEMENS RA GEN",58)	SS	TableSideOffset	1	PrivateTag
+(0019,"SIEMENS RA GEN",5a)	SS	TableIsoCenterHeight	1	PrivateTag
+(0019,"SIEMENS RA GEN",5c)	UN	Unknown	1	PrivateTag
+(0019,"SIEMENS RA GEN",5e)	SL	CollimationDataValid	1	PrivateTag
+(0019,"SIEMENS RA GEN",60)	SL	PeriSequenceNo	1	PrivateTag
+(0019,"SIEMENS RA GEN",62)	SL	PeriTotalScenes	1	PrivateTag
+(0019,"SIEMENS RA GEN",64)	SL	PeriOverlapTop	1	PrivateTag
+(0019,"SIEMENS RA GEN",66)	SL	PeriOverlapBottom	1	PrivateTag
+(0019,"SIEMENS RA GEN",68)	SL	RawImageNumber	1	PrivateTag
+(0019,"SIEMENS RA GEN",6a)	SL	XRayDataValid	1	PrivateTag
+(0019,"SIEMENS RA GEN",70)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",72)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",74)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",76)	SL	FillingAverageFactor	1	PrivateTag
+(0019,"SIEMENS RA GEN",78)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",7a)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",7c)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",7e)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",80)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",82)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",84)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",86)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",88)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",8a)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",8c)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",8e)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",92)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",94)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",96)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",98)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",9a)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA GEN",9c)	SL	IntensifierLevelCalibrationFactor	1	PrivateTag
+(0019,"SIEMENS RA GEN",9e)	SL	NativeReviewFlag	1	PrivateTag
+(0019,"SIEMENS RA GEN",a2)	SL	SceneNumber	1	PrivateTag
+(0019,"SIEMENS RA GEN",a4)	SS	AcquisitionMode	1	PrivateTag
+(0019,"SIEMENS RA GEN",a5)	SS	AcquisitonFrameRate	1	PrivateTag
+(0019,"SIEMENS RA GEN",a6)	SL	ECGFlag	1	PrivateTag
+(0019,"SIEMENS RA GEN",a7)	SL	AdditionalSceneData	1	PrivateTag
+(0019,"SIEMENS RA GEN",a8)	SL	FileCopyFlag	1	PrivateTag
+(0019,"SIEMENS RA GEN",a9)	SL	PhlebovisionFlag	1	PrivateTag
+(0019,"SIEMENS RA GEN",aa)	SL	Co2Flag	1	PrivateTag
+(0019,"SIEMENS RA GEN",ab)	SS	MaxSpeed	1	PrivateTag
+(0019,"SIEMENS RA GEN",ac)	SS	StepWidth	1	PrivateTag
+(0019,"SIEMENS RA GEN",ad)	SL	DigitalAcquisitionZoom	1	PrivateTag
+(0019,"SIEMENS RA GEN",ff)	SS	Internal	1-n	PrivateTag
+(0021,"SIEMENS RA GEN",15)	SS	ImagesInStudy	1	PrivateTag
+(0021,"SIEMENS RA GEN",20)	SS	ScenesInStudy	1	PrivateTag
+(0021,"SIEMENS RA GEN",25)	SS	ImagesInPhotofile	1	PrivateTag
+(0021,"SIEMENS RA GEN",27)	SS	PlaneBImagesExist	1	PrivateTag
+(0021,"SIEMENS RA GEN",28)	SS	NoOf2MBChunks	1	PrivateTag
+(0021,"SIEMENS RA GEN",30)	SS	ImagesInAllScenes	1	PrivateTag
+(0021,"SIEMENS RA GEN",40)	SS	ArchiveSWInternalVersion	1	PrivateTag
+
+(0011,"SIEMENS RA PLANE A",28)	SL	FluoroTimerA	1	PrivateTag
+(0011,"SIEMENS RA PLANE A",29)	SL	FluoroSkinDoseA	1	PrivateTag
+(0011,"SIEMENS RA PLANE A",2a)	SL	TotalSkinDoseA	1	PrivateTag
+(0011,"SIEMENS RA PLANE A",2b)	SL	FluoroDoseAreaProductA	1	PrivateTag
+(0011,"SIEMENS RA PLANE A",2c)	SL	TotalDoseAreaProductA	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",15)	LT	OfflineUID	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",18)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",19)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",1a)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",1b)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",1c)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",1d)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",1e)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",1f)	SS	Internal	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE A",20)	SS	SystemCalibFactorPlaneA	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",22)	SS	XRayParameterSetNo	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",24)	SS	XRaySystem	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",26)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",28)	SS	AcquiredDisplayMode	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",2a)	SS	AcquisitionDelay	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",2c)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",2e)	SS	MaxFramesLimit	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",30)	US	MaximumFrameSizeNIU	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",32)	SS	SubtractedFilterType	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",34)	SS	FilterFactorNative	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",36)	SS	AnatomicBackgroundFactor	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",38)	SS	WindowUpperLimitNative	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",3a)	SS	WindowLowerLimitNative	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",3c)	SS	WindowBrightnessPhase1	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",3e)	SS	WindowBrightnessPhase2	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",40)	SS	WindowContrastPhase1	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",42)	SS	WindowContrastPhase2	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",44)	SS	FilterFactorSub	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",46)	SS	PeakOpacified	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",48)	SL	MaskFrame	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",4a)	SL	BIHFrame	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",4c)	SS	CentBeamAngulationCaudCran	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",4e)	SS	CentBeamAngulationLRAnterior	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",50)	SS	LongitudinalPosition	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",52)	SS	SideOffset	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",54)	SS	IsoCenterHeight	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",56)	SS	ImageTwist	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",58)	SS	SourceImageDistance	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",5a)	SS	MechanicalMagnificationFactor	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",5c)	SL	CalibrationFlag	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",5e)	SL	CalibrationAngleCranCaud	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",60)	SL	CalibrationAngleRAOLAO	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",62)	SL	CalibrationTableToFloorDist	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",64)	SL	CalibrationIsocenterToFloorDist	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",66)	SL	CalibrationIsocenterToSourceDist	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",68)	SL	CalibrationSourceToII	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",6a)	SL	CalibrationIIZoom	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",6c)	SL	CalibrationIIField	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",6e)	SL	CalibrationFactor	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",70)	SL	CalibrationObjectToImageDistance	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",72)	SL	CalibrationSystemFactor	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE A",74)	SL	CalibrationSystemCorrection	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE A",76)	SL	CalibrationSystemIIFormats	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE A",78)	SL	CalibrationGantryDataValid	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",7a)	SS	CollimatorSquareBreadth	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",7c)	SS	CollimatorSquareHeight	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",7e)	SS	CollimatorSquareDiameter	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",80)	SS	CollimaterFingerTurnAngle	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",82)	SS	CollimaterFingerPosition	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",84)	SS	CollimaterDiaphragmTurnAngle	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",86)	SS	CollimaterDiaphragmPosition1	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",88)	SS	CollimaterDiaphragmPosition2	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",8a)	SS	CollimaterDiaphragmMode	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",8c)	SS	CollimaterBeamLimitBreadth	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",8e)	SS	CollimaterBeamLimitHeight	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",90)	SS	CollimaterBeamLimitDiameter	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",92)	SS	X-RayControlMOde	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",94)	SS	X-RaySystem	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",96)	SS	FocalSpot	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",98)	SS	ExposureControl	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",9a)	SL	XRayVoltage	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",9c)	SL	XRayCurrent	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",9e)	SL	XRayCurrentTimeProduct	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",a0)	SL	XRayPulseTime	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",a2)	SL	XRaySceneTimeFluoroClock	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",a4)	SS	MaximumPulseRate	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",a6)	SS	PulsesPerScene	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",a8)	SL	DoseAreaProductOfScene	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",aa)	SS	Dose	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",ac)	SS	DoseRate	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",ae)	SL	IIToCoverDistance	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",b0)	SS	LastFramePhase1	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",b1)	SS	FrameRatePhase1	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",b2)	SS	LastFramePhase2	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",b3)	SS	FrameRatePhase2	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",b4)	SS	LastFramePhase3	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",b5)	SS	FrameRatePhase3	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",b6)	SS	LastFramePhase4	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",b7)	SS	FrameRatePhase4	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",b8)	SS	GammaOfNativeImage	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",b9)	SS	GammaOfTVSystem	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",bb)	SL	PixelshiftX	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",bc)	SL	PixelshiftY	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",bd)	SL	MaskAverageFactor	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",be)	SL	BlankingCircleFlag	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",bf)	SL	CircleRowStart	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",c0)	SL	CircleRowEnd	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",c1)	SL	CircleColumnStart	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",c2)	SL	CircleColumnEnd	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",c3)	SL	CircleDiameter	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",c4)	SL	RectangularCollimaterFlag	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",c5)	SL	RectangleRowStart	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",c6)	SL	RectangleRowEnd	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",c7)	SL	RectangleColumnStart	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",c8)	SL	RectangleColumnEnd	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",c9)	SL	RectangleAngulation	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",ca)	SL	IrisCollimatorFlag	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",cb)	SL	IrisRowStart	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",cc)	SL	IrisRowEnd	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",cd)	SL	IrisColumnStart	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",ce)	SL	IrisColumnEnd	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",cf)	SL	IrisAngulation	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",d1)	SS	NumberOfFramesPlane	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",d2)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",d3)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",d4)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",d5)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",d6)	SS	Internal	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE A",d7)	SS	Internal	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE A",d8)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",d9)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",da)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",db)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",dc)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",dd)	SL	AnatomicBackground	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",de)	SL	AutoWindowBase	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE A",df)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE A",e0)	SL	Internal	1	PrivateTag
+
+(0011,"SIEMENS RA PLANE B",28)	SL	FluoroTimerB	1	PrivateTag
+(0011,"SIEMENS RA PLANE B",29)	SL	FluoroSkinDoseB	1	PrivateTag
+(0011,"SIEMENS RA PLANE B",2a)	SL	TotalSkinDoseB	1	PrivateTag
+(0011,"SIEMENS RA PLANE B",2b)	SL	FluoroDoseAreaProductB	1	PrivateTag
+(0011,"SIEMENS RA PLANE B",2c)	SL	TotalDoseAreaProductB	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",18)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",19)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",1a)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",1b)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",1c)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",1d)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",1e)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",1f)	SS	Internal	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",20)	SL	SystemCalibFactorPlaneB	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",22)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",24)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",26)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",28)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",2a)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",2c)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",2e)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",30)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",32)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",34)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",36)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",38)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",3a)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",3c)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",3e)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",40)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",42)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",44)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",46)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",48)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",4a)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",4c)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",4e)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",50)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",52)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",54)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",56)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",58)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",5a)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",5c)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",5e)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",60)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",62)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",64)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",66)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",68)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",6a)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",6c)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",6e)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",70)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",72)	UN	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",74)	UN	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",76)	UN	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",78)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",7a)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",7c)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",7e)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",80)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",82)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",84)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",86)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",88)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",8a)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",8c)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",8e)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",90)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",92)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",94)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",96)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",98)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",9a)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",9c)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",9e)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",a0)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",a2)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",a4)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",a6)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",a8)	US	Unknown	1-n	PrivateTag
+(0019,"SIEMENS RA PLANE B",aa)	US	Unknown	1	PrivateTag
+(0019,"SIEMENS RA PLANE B",ac)	US	Unknown	1	PrivateTag
+
+(0011,"SIEMENS RIS",10)	LT	PatientUID	1	PrivateTag
+(0011,"SIEMENS RIS",11)	LT	PatientID	1	PrivateTag
+(0011,"SIEMENS RIS",20)	DA	PatientRegistrationDate	1	PrivateTag
+(0011,"SIEMENS RIS",21)	TM	PatientRegistrationTime	1	PrivateTag
+(0011,"SIEMENS RIS",30)	LT	PatientnameRIS	1	PrivateTag
+(0011,"SIEMENS RIS",31)	LT	PatientprenameRIS	1	PrivateTag
+(0011,"SIEMENS RIS",40)	LT	PatientHospitalStatus	1	PrivateTag
+(0011,"SIEMENS RIS",41)	LT	MedicalAlerts	1	PrivateTag
+(0011,"SIEMENS RIS",42)	LT	ContrastAllergies	1	PrivateTag
+(0031,"SIEMENS RIS",10)	LT	RequestUID	1	PrivateTag
+(0031,"SIEMENS RIS",45)	LT	RequestingPhysician	1	PrivateTag
+(0031,"SIEMENS RIS",50)	LT	RequestedPhysician	1	PrivateTag
+(0033,"SIEMENS RIS",10)	LT	PatientStudyUID	1	PrivateTag
+
+(0021,"SIEMENS SMS-AX  ACQ 1.0",00)	US	AcquisitionType	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",01)	US	AcquisitionMode	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",02)	US	FootswitchIndex	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",03)	US	AcquisitionRoom	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",04)	SL	CurrentTimeProduct	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",05)	SL	Dose	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",06)	SL	SkinDosePercent	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",07)	SL	SkinDoseAccumulation	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",08)	SL	SkinDoseRate	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",0A)	UL	CopperFilter	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",0B)	US	MeasuringField	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",0C)	SS	PostBlankingCircle	3	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",0D)	SS	DynaAngles	2-2n	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",0E)	SS	TotalSteps	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",0F)	SL	DynaXRayInfo	3-3n	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",10)	US	ModalityLUTInputGamma	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",11)	US	ModalityLUTOutputGamma	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",12)	OB	SH_STPAR	1-n	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",13)	US	AcquisitionZoom	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",14)	SS	DynaAngulationStepWidth	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",15)	US	Harmonization	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",16)	US	DRSingleFlag	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",17)	SL	SourceToIsocenter	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",18)	US	PressureData	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",19)	SL	ECGIndexArray	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",1A)	US	FDFlag	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",1B)	OB	SH_ZOOM	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",1C)	OB	SH_COLPAR	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",1D)	US	K_Factor	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",1E)	US	EVE	8	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",1F)	SL	TotalSceneTime	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",20)	US	RestoreFlag	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",21)	US	StandMovementFlag	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",22)	US	FDRows	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",23)	US	FDColumns	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",24)	US	TableMovementFlag	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",25)	LO	OriginalOrganProgramName	1	PrivateTag
+(0021,"SIEMENS SMS-AX  ACQ 1.0",26)	DS	CrispyXPIFilter	1	PrivateTag
+
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",00)	US	ViewNative	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",01)	US	OriginalSeriesNumber	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",02)	US	OriginalImageNumber	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",03)	US	WinCenter	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",04)	US	WinWidth	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",05)	US	WinBrightness	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",06)	US	WinContrast	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",07)	US	OriginalFrameNumber	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",08)	US	OriginalMaskFrameNumber	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",09)	US	Opac	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",0A)	US	OriginalNumberOfFrames	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",0B)	DS	OriginalSceneDuration	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",0C)	LO	IdentifierLOID	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",0D)	SS	OriginalSceneVFRInfo	1-n	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",0E)	SS	OriginalFrameECGPosition	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",0F)	SS	OriginalECG1stFrameOffset_retired	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",10)	SS	ZoomFlag	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",11)	US	Flex	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",12)	US	NumberOfMaskFrames	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",13)	US	NumberOfFillFrames	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",14)	US	SeriesNumber	1	PrivateTag
+(0025,"SIEMENS SMS-AX  ORIGINAL IMAGE INFO 1.0",15)	IS	ImageNumber	1	PrivateTag
+
+(0023,"SIEMENS SMS-AX  QUANT 1.0",00)	DS	HorizontalCalibrationPixelSize	2	PrivateTag
+(0023,"SIEMENS SMS-AX  QUANT 1.0",01)	DS	VerticalCalibrationPixelSize	2	PrivateTag
+(0023,"SIEMENS SMS-AX  QUANT 1.0",02)	LO	CalibrationObject	1	PrivateTag
+(0023,"SIEMENS SMS-AX  QUANT 1.0",03)	DS	CalibrationObjectSize	1	PrivateTag
+(0023,"SIEMENS SMS-AX  QUANT 1.0",04)	LO	CalibrationMethod	1	PrivateTag
+(0023,"SIEMENS SMS-AX  QUANT 1.0",05)	ST	Filename	1	PrivateTag
+(0023,"SIEMENS SMS-AX  QUANT 1.0",06)	IS	FrameNumber	1	PrivateTag
+(0023,"SIEMENS SMS-AX  QUANT 1.0",07)	IS	CalibrationFactorMultiplicity	2	PrivateTag
+(0023,"SIEMENS SMS-AX  QUANT 1.0",08)	IS	CalibrationTODValue	1	PrivateTag
+
+(0019,"SIEMENS SMS-AX  VIEW 1.0",00)	US	ReviewMode	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",01)	US	AnatomicalBackgroundPercent	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",02)	US	NumberOfPhases	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",03)	US	ApplyAnatomicalBackground	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",04)	SS	PixelShiftArray	4-4n	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",05)	US	Brightness	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",06)	US	Contrast	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",07)	US	Enabled	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",08)	US	NativeEdgeEnhancementPercentGain	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",09)	SS	NativeEdgeEnhancementLUTIndex	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",0A)	SS	NativeEdgeEnhancementKernelSize	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",0B)	US	SubtrEdgeEnhancementPercentGain	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",0C)	SS	SubtrEdgeEnhancementLUTIndex	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",0D)	SS	SubtrEdgeEnhancementKernelSize	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",0E)	US	FadePercent	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",0F)	US	FlippedBeforeLateralityApplied	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",10)	US	ApplyFade	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",12)	US	Zoom	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",13)	SS	PanX	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",14)	SS	PanY	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",15)	SS	NativeEdgeEnhancementAdvPercGain	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",16)	SS	SubtrEdgeEnhancementAdvPercGain	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",17)	US	InvertFlag	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",1A)	OB	Quant1KOverlay	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",1B)	US	OriginalResolution	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",1C)	DS	AutoWindowCenter	1	PrivateTag
+(0019,"SIEMENS SMS-AX  VIEW 1.0",1D)	DS	AutoWindowWidth	1	PrivateTag
+
+(0009,"SIENET",01)	US	SIENETCommandField	1	PrivateTag
+(0009,"SIENET",14)	LT	ReceiverPLA	1	PrivateTag
+(0009,"SIENET",16)	US	TransferPriority	1	PrivateTag
+(0009,"SIENET",29)	LT	ActualUser	1	PrivateTag
+(0095,"SIENET",01)	LT	ExaminationFolderID	1	PrivateTag
+(0095,"SIENET",04)	UL	FolderReportedStatus	1	PrivateTag
+(0095,"SIENET",05)	LT	FolderReportingRadiologist	1	PrivateTag
+(0095,"SIENET",07)	LT	SIENETISAPLA	1	PrivateTag
+(0099,"SIENET",02)	UL	DataObjectAttributes	1	PrivateTag
+
+(0009,"SPI RELEASE 1",10)	LT	Comments	1	PrivateTag
+(0009,"SPI RELEASE 1",15)	LO	SPIImageUID	1	PrivateTag
+(0009,"SPI RELEASE 1",40)	US	DataObjectType	1	PrivateTag
+(0009,"SPI RELEASE 1",41)	LO	DataObjectSubtype	1	PrivateTag
+(0011,"SPI RELEASE 1",10)	LO	Organ	1	PrivateTag
+(0011,"SPI RELEASE 1",15)	LO	AllergyIndication	1	PrivateTag
+(0011,"SPI RELEASE 1",20)	LO	Pregnancy	1	PrivateTag
+(0029,"SPI RELEASE 1",60)	LT	CompressionAlgorithm	1	PrivateTag
+
+(0009,"SPI Release 1",10)	LT	Comments	1	PrivateTag
+(0009,"SPI Release 1",15)	LO	SPIImageUID	1	PrivateTag
+(0009,"SPI Release 1",40)	US	DataObjectType	1	PrivateTag
+(0009,"SPI Release 1",41)	LO	DataObjectSubtype	1	PrivateTag
+(0011,"SPI Release 1",10)	LO	Organ	1	PrivateTag
+(0011,"SPI Release 1",15)	LO	AllergyIndication	1	PrivateTag
+(0011,"SPI Release 1",20)	LO	Pregnancy	1	PrivateTag
+(0029,"SPI Release 1",60)	LT	CompressionAlgorithm	1	PrivateTag
+
+(0009,"SPI",10)	LO	Comments	1	PrivateTag
+(0009,"SPI",15)	LO	SPIImageUID	1	PrivateTag
+(0009,"SPI",40)	US	DataObjectType	1	PrivateTag
+(0009,"SPI",41)	LT	DataObjectSubtype	1	PrivateTag
+(0011,"SPI",10)	LT	Organ	1	PrivateTag
+(0011,"SPI",15)	LT	AllergyIndication	1	PrivateTag
+(0011,"SPI",20)	LT	Pregnancy	1	PrivateTag
+(0029,"SPI",60)	LT	CompressionAlgorithm	1	PrivateTag
+
+(0011,"SPI RELEASE 1",10)	LO	Organ	1	PrivateTag
+(0011,"SPI RELEASE 1",15)	LO	AllergyIndication	1	PrivateTag
+(0011,"SPI RELEASE 1",20)	LO	Pregnancy	1	PrivateTag
+
+(0009,"SPI-P Release 1",00)	LT	DataObjectRecognitionCode	1	PrivateTag
+(0009,"SPI-P Release 1",04)	LO	ImageDataConsistence	1	PrivateTag
+(0009,"SPI-P Release 1",08)	US	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",12)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",15)	LO	UniqueIdentifier	1	PrivateTag
+(0009,"SPI-P Release 1",16)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",18)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",21)	LT	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",31)	LT	PACSUniqueIdentifier	1	PrivateTag
+(0009,"SPI-P Release 1",34)	LT	ClusterUniqueIdentifier	1	PrivateTag
+(0009,"SPI-P Release 1",38)	LT	SystemUniqueIdentifier	1	PrivateTag
+(0009,"SPI-P Release 1",39)	LT	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",51)	LT	StudyUniqueIdentifier	1	PrivateTag
+(0009,"SPI-P Release 1",61)	LT	SeriesUniqueIdentifier	1	PrivateTag
+(0009,"SPI-P Release 1",91)	LT	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",f2)	LT	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",f3)	UN	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",f4)	LT	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",f5)	UN	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1",f7)	LT	Unknown	1	PrivateTag
+(0011,"SPI-P Release 1",10)	LT	PatientEntryID	1	PrivateTag
+(0011,"SPI-P Release 1",21)	UN	Unknown	1	PrivateTag
+(0011,"SPI-P Release 1",22)	UN	Unknown	1	PrivateTag
+(0011,"SPI-P Release 1",31)	UN	Unknown	1	PrivateTag
+(0011,"SPI-P Release 1",32)	UN	Unknown	1	PrivateTag
+(0019,"SPI-P Release 1",00)	UN	Unknown	1	PrivateTag
+(0019,"SPI-P Release 1",01)	UN	Unknown	1	PrivateTag
+(0019,"SPI-P Release 1",02)	UN	Unknown	1	PrivateTag
+(0019,"SPI-P Release 1",10)	US	MainsFrequency	1	PrivateTag
+(0019,"SPI-P Release 1",25)	LT	OriginalPixelDataQuality	1-n	PrivateTag
+(0019,"SPI-P Release 1",30)	US	ECGTriggering	1	PrivateTag
+(0019,"SPI-P Release 1",31)	UN	ECG1Offset	1	PrivateTag
+(0019,"SPI-P Release 1",32)	UN	ECG2Offset1	1	PrivateTag
+(0019,"SPI-P Release 1",33)	UN	ECG2Offset2	1	PrivateTag
+(0019,"SPI-P Release 1",50)	US	VideoScanMode	1	PrivateTag
+(0019,"SPI-P Release 1",51)	US	VideoLineRate	1	PrivateTag
+(0019,"SPI-P Release 1",60)	US	XrayTechnique	1	PrivateTag
+(0019,"SPI-P Release 1",61)	DS	ImageIdentifierFromat	1	PrivateTag
+(0019,"SPI-P Release 1",62)	US	IrisDiaphragm	1	PrivateTag
+(0019,"SPI-P Release 1",63)	CS	Filter	1	PrivateTag
+(0019,"SPI-P Release 1",64)	CS	CineParallel	1	PrivateTag
+(0019,"SPI-P Release 1",65)	CS	CineMaster	1	PrivateTag
+(0019,"SPI-P Release 1",70)	US	ExposureChannel	1	PrivateTag
+(0019,"SPI-P Release 1",71)	UN	ExposureChannelFirstImage	1	PrivateTag
+(0019,"SPI-P Release 1",72)	US	ProcessingChannel	1	PrivateTag
+(0019,"SPI-P Release 1",80)	DS	AcquisitionDelay	1	PrivateTag
+(0019,"SPI-P Release 1",81)	UN	RelativeImageTime	1	PrivateTag
+(0019,"SPI-P Release 1",90)	CS	VideoWhiteCompression	1	PrivateTag
+(0019,"SPI-P Release 1",a0)	US	Angulation	1	PrivateTag
+(0019,"SPI-P Release 1",a1)	US	Rotation	1	PrivateTag
+(0021,"SPI-P Release 1",12)	LT	SeriesUniqueIdentifier	1	PrivateTag
+(0021,"SPI-P Release 1",14)	LT	Unknown	1	PrivateTag
+(0029,"SPI-P Release 1",00)	DS	Unknown	4	PrivateTag
+(0029,"SPI-P Release 1",20)	DS	PixelAspectRatio	1	PrivateTag
+(0029,"SPI-P Release 1",25)	LO	ProcessedPixelDataQuality	1-n	PrivateTag
+(0029,"SPI-P Release 1",30)	LT	Unknown	1	PrivateTag
+(0029,"SPI-P Release 1",38)	US	Unknown	1	PrivateTag
+(0029,"SPI-P Release 1",60)	LT	Unknown	1	PrivateTag
+(0029,"SPI-P Release 1",61)	LT	Unknown	1	PrivateTag
+(0029,"SPI-P Release 1",67)	LT	Unknown	1	PrivateTag
+(0029,"SPI-P Release 1",70)	LT	WindowID	1	PrivateTag
+(0029,"SPI-P Release 1",71)	CS	VideoInvertSubtracted	1	PrivateTag
+(0029,"SPI-P Release 1",72)	CS	VideoInvertNonsubtracted	1	PrivateTag
+(0029,"SPI-P Release 1",77)	CS	WindowSelectStatus	1	PrivateTag
+(0029,"SPI-P Release 1",78)	LT	ECGDisplayPrintingID	1	PrivateTag
+(0029,"SPI-P Release 1",79)	CS	ECGDisplayPrinting	1	PrivateTag
+(0029,"SPI-P Release 1",7e)	CS	ECGDisplayPrintingEnableStatus	1	PrivateTag
+(0029,"SPI-P Release 1",7f)	CS	ECGDisplayPrintingSelectStatus	1	PrivateTag
+(0029,"SPI-P Release 1",80)	LT	PhysiologicalDisplayID	1	PrivateTag
+(0029,"SPI-P Release 1",81)	US	PreferredPhysiologicalChannelDisplay	1	PrivateTag
+(0029,"SPI-P Release 1",8e)	CS	PhysiologicalDisplayEnableStatus	1	PrivateTag
+(0029,"SPI-P Release 1",8f)	CS	PhysiologicalDisplaySelectStatus	1	PrivateTag
+(0029,"SPI-P Release 1",c0)	LT	FunctionalShutterID	1	PrivateTag
+(0029,"SPI-P Release 1",c1)	US	FieldOfShutter	1	PrivateTag
+(0029,"SPI-P Release 1",c5)	LT	FieldOfShutterRectangle	1	PrivateTag
+(0029,"SPI-P Release 1",ce)	CS	ShutterEnableStatus	1	PrivateTag
+(0029,"SPI-P Release 1",cf)	CS	ShutterSelectStatus	1	PrivateTag
+(7FE1,"SPI-P Release 1",10)	ox	PixelData	1	PrivateTag
+
+(0009,"SPI-P Release 1;1",c0)	LT	Unknown	1	PrivateTag
+(0009,"SPI-P Release 1;1",c1)	LT	Unknown	1	PrivateTag
+(0019,"SPI-P Release 1;1",00)	UN	PhysiologicalDataType	1	PrivateTag
+(0019,"SPI-P Release 1;1",01)	UN	PhysiologicalDataChannelAndKind	1	PrivateTag
+(0019,"SPI-P Release 1;1",02)	US	SampleBitsAllocated	1	PrivateTag
+(0019,"SPI-P Release 1;1",03)	US	SampleBitsStored	1	PrivateTag
+(0019,"SPI-P Release 1;1",04)	US	SampleHighBit	1	PrivateTag
+(0019,"SPI-P Release 1;1",05)	US	SampleRepresentation	1	PrivateTag
+(0019,"SPI-P Release 1;1",06)	UN	SmallestSampleValue	1	PrivateTag
+(0019,"SPI-P Release 1;1",07)	UN	LargestSampleValue	1	PrivateTag
+(0019,"SPI-P Release 1;1",08)	UN	NumberOfSamples	1	PrivateTag
+(0019,"SPI-P Release 1;1",09)	UN	SampleData	1	PrivateTag
+(0019,"SPI-P Release 1;1",0a)	UN	SampleRate	1	PrivateTag
+(0019,"SPI-P Release 1;1",10)	UN	PhysiologicalDataType2	1	PrivateTag
+(0019,"SPI-P Release 1;1",11)	UN	PhysiologicalDataChannelAndKind2	1	PrivateTag
+(0019,"SPI-P Release 1;1",12)	US	SampleBitsAllocated2	1	PrivateTag
+(0019,"SPI-P Release 1;1",13)	US	SampleBitsStored2	1	PrivateTag
+(0019,"SPI-P Release 1;1",14)	US	SampleHighBit2	1	PrivateTag
+(0019,"SPI-P Release 1;1",15)	US	SampleRepresentation2	1	PrivateTag
+(0019,"SPI-P Release 1;1",16)	UN	SmallestSampleValue2	1	PrivateTag
+(0019,"SPI-P Release 1;1",17)	UN	LargestSampleValue2	1	PrivateTag
+(0019,"SPI-P Release 1;1",18)	UN	NumberOfSamples2	1	PrivateTag
+(0019,"SPI-P Release 1;1",19)	UN	SampleData2	1	PrivateTag
+(0019,"SPI-P Release 1;1",1a)	UN	SampleRate2	1	PrivateTag
+(0029,"SPI-P Release 1;1",00)	LT	ZoomID	1	PrivateTag
+(0029,"SPI-P Release 1;1",01)	DS	ZoomRectangle	1-n	PrivateTag
+(0029,"SPI-P Release 1;1",03)	DS	ZoomFactor	1	PrivateTag
+(0029,"SPI-P Release 1;1",04)	US	ZoomFunction	1	PrivateTag
+(0029,"SPI-P Release 1;1",0e)	CS	ZoomEnableStatus	1	PrivateTag
+(0029,"SPI-P Release 1;1",0f)	CS	ZoomSelectStatus	1	PrivateTag
+(0029,"SPI-P Release 1;1",40)	LT	MagnifyingGlassID	1	PrivateTag
+(0029,"SPI-P Release 1;1",41)	DS	MagnifyingGlassRectangle	1-n	PrivateTag
+(0029,"SPI-P Release 1;1",43)	DS	MagnifyingGlassFactor	1	PrivateTag
+(0029,"SPI-P Release 1;1",44)	US	MagnifyingGlassFunction	1	PrivateTag
+(0029,"SPI-P Release 1;1",4e)	CS	MagnifyingGlassEnableStatus	1	PrivateTag
+(0029,"SPI-P Release 1;1",4f)	CS	MagnifyingGlassSelectStatus	1	PrivateTag
+
+(0029,"SPI-P Release 1;2",00)	LT	SubtractionMaskID	1	PrivateTag
+(0029,"SPI-P Release 1;2",04)	UN	MaskingFunction	1	PrivateTag
+(0029,"SPI-P Release 1;2",0c)	UN	ProprietaryMaskingParameters	1	PrivateTag
+(0029,"SPI-P Release 1;2",1e)	CS	SubtractionMaskEnableStatus	1	PrivateTag
+(0029,"SPI-P Release 1;2",1f)	CS	SubtractionMaskSelectStatus	1	PrivateTag
+(0029,"SPI-P Release 1;3",00)	LT	ImageEnhancementID	1	PrivateTag
+(0029,"SPI-P Release 1;3",01)	LT	ImageEnhancement	1	PrivateTag
+(0029,"SPI-P Release 1;3",02)	LT	ConvolutionID	1	PrivateTag
+(0029,"SPI-P Release 1;3",03)	LT	ConvolutionType	1	PrivateTag
+(0029,"SPI-P Release 1;3",04)	LT	ConvolutionKernelSizeID	1	PrivateTag
+(0029,"SPI-P Release 1;3",05)	US	ConvolutionKernelSize	2	PrivateTag
+(0029,"SPI-P Release 1;3",06)	US	ConvolutionKernel	1-n	PrivateTag
+(0029,"SPI-P Release 1;3",0c)	DS	EnhancementGain	1	PrivateTag
+(0029,"SPI-P Release 1;3",1e)	CS	ImageEnhancementEnableStatus	1	PrivateTag
+(0029,"SPI-P Release 1;3",1f)	CS	ImageEnhancementSelectStatus	1	PrivateTag
+
+(0011,"SPI-P Release 2;1",18)	LT	Unknown	1	PrivateTag
+(0023,"SPI-P Release 2;1",0d)	UI	Unknown	1	PrivateTag
+(0023,"SPI-P Release 2;1",0e)	UI	Unknown	1	PrivateTag
+
+(0009,"SPI-P-GV-CT Release 1",00)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P-GV-CT Release 1",10)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P-GV-CT Release 1",20)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P-GV-CT Release 1",30)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P-GV-CT Release 1",40)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P-GV-CT Release 1",50)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P-GV-CT Release 1",60)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P-GV-CT Release 1",70)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P-GV-CT Release 1",75)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P-GV-CT Release 1",80)	LO	Unknown	1	PrivateTag
+(0009,"SPI-P-GV-CT Release 1",90)	LO	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",08)	IS	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",09)	IS	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",0a)	IS	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",10)	LO	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",20)	TM	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",50)	LO	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",60)	DS	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",61)	US	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",63)	LO	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",64)	US	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",65)	IS	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",70)	LT	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",80)	LO	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",81)	LO	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",90)	LO	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",a0)	LO	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",a1)	US	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",a2)	US	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",a3)	US	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",b0)	LO	Unknown	1	PrivateTag
+(0019,"SPI-P-GV-CT Release 1",b1)	LO	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",20)	LO	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",30)	DS	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",40)	LO	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",50)	LO	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",60)	DS	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",70)	DS	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",80)	DS	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",90)	DS	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",a0)	US	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",a1)	DS	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",a2)	DS	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",a3)	LT	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",a4)	LT	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",b0)	LO	Unknown	1	PrivateTag
+(0021,"SPI-P-GV-CT Release 1",c0)	LO	Unknown	1	PrivateTag
+(0029,"SPI-P-GV-CT Release 1",10)	LO	Unknown	1	PrivateTag
+(0029,"SPI-P-GV-CT Release 1",30)	UL	Unknown	1	PrivateTag
+(0029,"SPI-P-GV-CT Release 1",31)	UL	Unknown	1	PrivateTag
+(0029,"SPI-P-GV-CT Release 1",32)	UL	Unknown	1	PrivateTag
+(0029,"SPI-P-GV-CT Release 1",33)	UL	Unknown	1	PrivateTag
+(0029,"SPI-P-GV-CT Release 1",80)	LO	Unknown	1	PrivateTag
+(0029,"SPI-P-GV-CT Release 1",90)	LO	Unknown	1	PrivateTag
+(0029,"SPI-P-GV-CT Release 1",d0)	IS	Unknown	1	PrivateTag
+(0029,"SPI-P-GV-CT Release 1",d1)	IS	Unknown	1	PrivateTag
+
+(0019,"SPI-P-PCR Release 2",30)	US	Unknown	1	PrivateTag
+
+(0021,"SPI-P-Private-CWS Release 1",00)	LT	WindowOfImagesID	1	PrivateTag
+(0021,"SPI-P-Private-CWS Release 1",01)	CS	WindowOfImagesType	1	PrivateTag
+(0021,"SPI-P-Private-CWS Release 1",02)	IS	WindowOfImagesScope	1-n	PrivateTag
+
+(0019,"SPI-P-Private-DCI Release 1",10)	UN	ECGTimeMapDataBitsAllocated	1	PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",11)	UN	ECGTimeMapDataBitsStored	1	PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",12)	UN	ECGTimeMapDataHighBit	1	PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",13)	UN	ECGTimeMapDataRepresentation	1	PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",14)	UN	ECGTimeMapDataSmallestDataValue	1	PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",15)	UN	ECGTimeMapDataLargestDataValue	1	PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",16)	UN	ECGTimeMapDataNumberOfDataValues	1	PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",17)	UN	ECGTimeMapData	1	PrivateTag
+
+(0021,"SPI-P-Private_CDS Release 1",40)	IS	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_CDS Release 1",00)	UN	Unknown	1	PrivateTag
+
+(0019,"SPI-P-Private_ICS Release 1",30)	DS	Unknown	1	PrivateTag
+(0019,"SPI-P-Private_ICS Release 1",31)	LO	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",08)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",0f)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",10)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",1b)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",1c)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",21)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",43)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",44)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",4C)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",67)	LO	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",68)	US	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",6A)	LO	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",6B)	US	Unknown	1	PrivateTag
+
+(0029,"SPI-P-Private_ICS Release 1;1",00)	SL	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;1",05)	FL	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;1",06)	FL	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;1",20)	FL	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;1",21)	FL	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;1",CD)	SQ	Unknown	1	PrivateTag
+
+(0029,"SPI-P-Private_ICS Release 1;2",00)	FD	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;2",01)	FD	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;2",02)	FD	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;2",03)	SL	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;2",04)	SL	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;2",05)	SL	Unknown	1	PrivateTag
+
+(0029,"SPI-P-Private_ICS Release 1;3",C0)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;3",C1)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;3",C2)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;3",C3)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;3",C4)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;3",C5)	SQ	Unknown	1	PrivateTag
+
+(0029,"SPI-P-Private_ICS Release 1;4",02)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;4",9A)	SQ	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;4",E0)	SQ	Unknown	1	PrivateTag
+
+(0029,"SPI-P-Private_ICS Release 1;5",50)	CS	Unknown	1	PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;5",55)	CS	Unknown	1	PrivateTag
+
+(0019,"SPI-P-XSB-DCI Release 1",10)	LT	VideoBeamBoost	1	PrivateTag
+(0019,"SPI-P-XSB-DCI Release 1",11)	US	ChannelGeneratingVideoSync	1	PrivateTag
+(0019,"SPI-P-XSB-DCI Release 1",12)	US	VideoGain	1	PrivateTag
+(0019,"SPI-P-XSB-DCI Release 1",13)	US	VideoOffset	1	PrivateTag
+(0019,"SPI-P-XSB-DCI Release 1",20)	DS	RTDDataCompressionFactor	1	PrivateTag
+
+(0029,"Silhouette Annot V1.0",11)	IS	AnnotationName	1	PrivateTag
+(0029,"Silhouette Annot V1.0",12)	LT	AnnotationFont	1	PrivateTag
+(0029,"Silhouette Annot V1.0",13)	LT	AnnotationTextForegroundColor	1	PrivateTag
+(0029,"Silhouette Annot V1.0",14)	LT	AnnotationTextBackgroundColor	1	PrivateTag
+(0029,"Silhouette Annot V1.0",15)	UL	AnnotationTextBackingMode	1	PrivateTag
+(0029,"Silhouette Annot V1.0",16)	UL	AnnotationTextJustification	1	PrivateTag
+(0029,"Silhouette Annot V1.0",17)	UL	AnnotationTextLocation	1	PrivateTag
+(0029,"Silhouette Annot V1.0",18)	LT	AnnotationTextString	1	PrivateTag
+(0029,"Silhouette Annot V1.0",19)	UL	AnnotationTextAttachMode	1	PrivateTag
+(0029,"Silhouette Annot V1.0",20)	UL	AnnotationTextCursorMode	1	PrivateTag
+(0029,"Silhouette Annot V1.0",21)	UL	AnnotationTextShadowOffsetX	1	PrivateTag
+(0029,"Silhouette Annot V1.0",22)	UL	AnnotationTextShadowOffsetY	1	PrivateTag
+(0029,"Silhouette Annot V1.0",23)	LT	AnnotationLineColor	1	PrivateTag
+(0029,"Silhouette Annot V1.0",24)	UL	AnnotationLineThickness	1	PrivateTag
+(0029,"Silhouette Annot V1.0",25)	UL	AnnotationLineType	1	PrivateTag
+(0029,"Silhouette Annot V1.0",26)	UL	AnnotationLineStyle	1	PrivateTag
+(0029,"Silhouette Annot V1.0",27)	UL	AnnotationLineDashLength	1	PrivateTag
+(0029,"Silhouette Annot V1.0",28)	UL	AnnotationLineAttachMode	1	PrivateTag
+(0029,"Silhouette Annot V1.0",29)	UL	AnnotationLinePointCount	1	PrivateTag
+(0029,"Silhouette Annot V1.0",30)	FD	AnnotationLinePoints	1	PrivateTag
+(0029,"Silhouette Annot V1.0",31)	UL	AnnotationLineControlSize	1	PrivateTag
+(0029,"Silhouette Annot V1.0",32)	LT	AnnotationMarkerColor	1	PrivateTag
+(0029,"Silhouette Annot V1.0",33)	UL	AnnotationMarkerType	1	PrivateTag
+(0029,"Silhouette Annot V1.0",34)	UL	AnnotationMarkerSize	1	PrivateTag
+(0029,"Silhouette Annot V1.0",35)	FD	AnnotationMarkerLocation	1	PrivateTag
+(0029,"Silhouette Annot V1.0",36)	UL	AnnotationMarkerAttachMode	1	PrivateTag
+(0029,"Silhouette Annot V1.0",37)	LT	AnnotationGeomColor	1	PrivateTag
+(0029,"Silhouette Annot V1.0",38)	UL	AnnotationGeomThickness	1	PrivateTag
+(0029,"Silhouette Annot V1.0",39)	UL	AnnotationGeomLineStyle	1	PrivateTag
+(0029,"Silhouette Annot V1.0",40)	UL	AnnotationGeomDashLength	1	PrivateTag
+(0029,"Silhouette Annot V1.0",41)	UL	AnnotationGeomFillPattern	1	PrivateTag
+(0029,"Silhouette Annot V1.0",42)	UL	AnnotationInteractivity	1	PrivateTag
+(0029,"Silhouette Annot V1.0",43)	FD	AnnotationArrowLength	1	PrivateTag
+(0029,"Silhouette Annot V1.0",44)	FD	AnnotationArrowAngle	1	PrivateTag
+(0029,"Silhouette Annot V1.0",45)	UL	AnnotationDontSave	1	PrivateTag
+
+(0029,"Silhouette Graphics Export V1.0",00)	UI	Unknown	1	PrivateTag
+
+(0029,"Silhouette Line V1.0",11)	IS	LineName	1	PrivateTag
+(0029,"Silhouette Line V1.0",12)	LT	LineNameFont	1	PrivateTag
+(0029,"Silhouette Line V1.0",13)	UL	LineNameDisplay	1	PrivateTag
+(0029,"Silhouette Line V1.0",14)	LT	LineNormalColor	1	PrivateTag
+(0029,"Silhouette Line V1.0",15)	UL	LineType	1	PrivateTag
+(0029,"Silhouette Line V1.0",16)	UL	LineThickness	1	PrivateTag
+(0029,"Silhouette Line V1.0",17)	UL	LineStyle	1	PrivateTag
+(0029,"Silhouette Line V1.0",18)	UL	LineDashLength	1	PrivateTag
+(0029,"Silhouette Line V1.0",19)	UL	LineInteractivity	1	PrivateTag
+(0029,"Silhouette Line V1.0",20)	LT	LineMeasurementColor	1	PrivateTag
+(0029,"Silhouette Line V1.0",21)	LT	LineMeasurementFont	1	PrivateTag
+(0029,"Silhouette Line V1.0",22)	UL	LineMeasurementDashLength	1	PrivateTag
+(0029,"Silhouette Line V1.0",23)	UL	LinePointSpace	1	PrivateTag
+(0029,"Silhouette Line V1.0",24)	FD	LinePoints	1	PrivateTag
+(0029,"Silhouette Line V1.0",25)	UL	LineControlPointSize	1	PrivateTag
+(0029,"Silhouette Line V1.0",26)	UL	LineControlPointSpace	1	PrivateTag
+(0029,"Silhouette Line V1.0",27)	FD	LineControlPoints	1	PrivateTag
+(0029,"Silhouette Line V1.0",28)	LT	LineLabel	1	PrivateTag
+(0029,"Silhouette Line V1.0",29)	UL	LineDontSave	1	PrivateTag
+
+(0029,"Silhouette ROI V1.0",11)	IS	ROIName	1	PrivateTag
+(0029,"Silhouette ROI V1.0",12)	LT	ROINameFont	1	PrivateTag
+(0029,"Silhouette ROI V1.0",13)	LT	ROINormalColor	1	PrivateTag
+(0029,"Silhouette ROI V1.0",14)	UL	ROIFillPattern	1	PrivateTag
+(0029,"Silhouette ROI V1.0",15)	UL	ROIBpSeg	1	PrivateTag
+(0029,"Silhouette ROI V1.0",16)	UN	ROIBpSegPairs	1	PrivateTag
+(0029,"Silhouette ROI V1.0",17)	UL	ROISeedSpace	1	PrivateTag
+(0029,"Silhouette ROI V1.0",18)	UN	ROISeeds	1	PrivateTag
+(0029,"Silhouette ROI V1.0",19)	UL	ROILineThickness	1	PrivateTag
+(0029,"Silhouette ROI V1.0",20)	UL	ROILineStyle	1	PrivateTag
+(0029,"Silhouette ROI V1.0",21)	UL	ROILineDashLength	1	PrivateTag
+(0029,"Silhouette ROI V1.0",22)	UL	ROIInteractivity	1	PrivateTag
+(0029,"Silhouette ROI V1.0",23)	UL	ROINamePosition	1	PrivateTag
+(0029,"Silhouette ROI V1.0",24)	UL	ROINameDisplay	1	PrivateTag
+(0029,"Silhouette ROI V1.0",25)	LT	ROILabel	1	PrivateTag
+(0029,"Silhouette ROI V1.0",26)	UL	ROIShape	1	PrivateTag
+(0029,"Silhouette ROI V1.0",27)	FD	ROIShapeTilt	1	PrivateTag
+(0029,"Silhouette ROI V1.0",28)	UL	ROIShapePointsCount	1	PrivateTag
+(0029,"Silhouette ROI V1.0",29)	UL	ROIShapePointsSpace	1	PrivateTag
+(0029,"Silhouette ROI V1.0",30)	FD	ROIShapePoints	1	PrivateTag
+(0029,"Silhouette ROI V1.0",31)	UL	ROIShapeControlPointsCount	1	PrivateTag
+(0029,"Silhouette ROI V1.0",32)	UL	ROIShapeControlPointsSpace	1	PrivateTag
+(0029,"Silhouette ROI V1.0",33)	FD	ROIShapeControlPoints	1	PrivateTag
+(0029,"Silhouette ROI V1.0",34)	UL	ROIDontSave	1	PrivateTag
+
+(0029,"Silhouette Sequence Ids V1.0",41)	SQ	Unknown	1	PrivateTag
+(0029,"Silhouette Sequence Ids V1.0",42)	SQ	Unknown	1	PrivateTag
+(0029,"Silhouette Sequence Ids V1.0",43)	SQ	Unknown	1	PrivateTag
+
+(0029,"Silhouette V1.0",13)	UL	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",14)	UL	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",17)	UN	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",18)	UN	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",19)	UL	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",1a)	UN	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",1b)	UL	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",1c)	UL	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",1d)	UN	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",1e)	UN	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",21)	US	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",22)	US	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",23)	US	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",24)	US	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",25)	US	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",27)	UN	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",28)	UN	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",29)	UN	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",30)	UN	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",52)	US	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",53)	LT	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",54)	UN	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",55)	LT	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",56)	LT	Unknown	1	PrivateTag
+(0029,"Silhouette V1.0",57)	UN	Unknown	1	PrivateTag
+
+(0135,"SONOWAND AS",10)	LO	UltrasoundScannerName	1	PrivateTag
+(0135,"SONOWAND AS",11)	LO	TransducerSerial	1	PrivateTag
+(0135,"SONOWAND AS",12)	LO	ProbeApplication	1	PrivateTag
+
+(0017,"SVISION",00)	LO	ExtendedBodyPart	1	PrivateTag
+(0017,"SVISION",10)	LO	ExtendedViewPosition	1	PrivateTag
+(0017,"SVISION",F0)	IS	ImagesSOPClass	1	PrivateTag
+(0019,"SVISION",00)	IS	AECField	1	PrivateTag
+(0019,"SVISION",01)	IS	AECFilmScreen	1	PrivateTag
+(0019,"SVISION",02)	IS	AECDensity	1	PrivateTag
+(0019,"SVISION",10)	IS	PatientThickness	1	PrivateTag
+(0019,"SVISION",18)	IS	BeamDistance	1	PrivateTag
+(0019,"SVISION",20)	IS	WorkstationNumber	1	PrivateTag
+(0019,"SVISION",28)	IS	TubeNumber	1	PrivateTag
+(0019,"SVISION",30)	IS	BuckyGrid	1	PrivateTag
+(0019,"SVISION",34)	IS	Focus	1	PrivateTag
+(0019,"SVISION",38)	IS	Child	1	PrivateTag
+(0019,"SVISION",40)	IS	CollimatorDistanceX	1	PrivateTag
+(0019,"SVISION",41)	IS	CollimatorDistanceY	1	PrivateTag
+(0019,"SVISION",50)	IS	CentralBeamHeight	1	PrivateTag
+(0019,"SVISION",60)	IS	BuckyAngle	1	PrivateTag
+(0019,"SVISION",68)	IS	CArmAngle	1	PrivateTag
+(0019,"SVISION",69)	IS	CollimatorAngle	1	PrivateTag
+(0019,"SVISION",70)	IS	FilterNumber	1	PrivateTag
+(0019,"SVISION",74)	LO	FilterMaterial1	1	PrivateTag
+(0019,"SVISION",75)	LO	FilterMaterial2	1	PrivateTag
+(0019,"SVISION",78)	DS	FilterThickness1	1	PrivateTag
+(0019,"SVISION",79)	DS	FilterThickness2	1	PrivateTag
+(0019,"SVISION",80)	IS	BuckyFormat	1	PrivateTag
+(0019,"SVISION",81)	IS	ObjectPosition	1	PrivateTag
+(0019,"SVISION",90)	LO	DeskCommand	1	PrivateTag
+(0019,"SVISION",A0)	DS	ExtendedExposureTime	1	PrivateTag
+(0019,"SVISION",A1)	DS	ActualExposureTime	1	PrivateTag
+(0019,"SVISION",A8)	DS	ExtendedXRayTubeCurrent	1	PrivateTag
+(0021,"SVISION",00)	DS	NoiseReduction	1	PrivateTag
+(0021,"SVISION",01)	DS	ContrastAmplification	1	PrivateTag
+(0021,"SVISION",02)	DS	EdgeContrastBoosting	1	PrivateTag
+(0021,"SVISION",03)	DS	LatitudeReduction	1	PrivateTag
+(0021,"SVISION",10)	LO	FindRangeAlgorithm	1	PrivateTag
+(0021,"SVISION",11)	DS	ThresholdCAlgorithm	1	PrivateTag
+(0021,"SVISION",20)	LO	SensometricCurve	1	PrivateTag
+(0021,"SVISION",30)	DS	LowerWindowOffset	1	PrivateTag
+(0021,"SVISION",31)	DS	UpperWindowOffset	1	PrivateTag
+(0021,"SVISION",40)	DS	MinPrintableDensity	1	PrivateTag
+(0021,"SVISION",41)	DS	MaxPrintableDensity	1	PrivateTag
+(0021,"SVISION",90)	DS	Brightness	1	PrivateTag
+(0021,"SVISION",91)	DS	Contrast	1	PrivateTag
+(0021,"SVISION",92)	DS	ShapeFactor	1	PrivateTag
+(0023,"SVISION",00)	LO	ImageLaterality	1	PrivateTag
+(0023,"SVISION",01)	IS	LetterPosition	1	PrivateTag
+(0023,"SVISION",02)	IS	BurnedInAnnotation	1	PrivateTag
+(0023,"SVISION",03)	LO	Unknown	1	PrivateTag
+(0023,"SVISION",F0)	IS	ImageSOPClass	1	PrivateTag
+(0025,"SVISION",00)	IS	OriginalImage	1	PrivateTag
+(0025,"SVISION",01)	IS	NotProcessedImage	1	PrivateTag
+(0025,"SVISION",02)	IS	CutOutImage	1	PrivateTag
+(0025,"SVISION",03)	IS	DuplicatedImage	1	PrivateTag
+(0025,"SVISION",04)	IS	StoredImage	1	PrivateTag
+(0025,"SVISION",05)	IS	RetrievedImage	1	PrivateTag
+(0025,"SVISION",06)	IS	RemoteImage	1	PrivateTag
+(0025,"SVISION",07)	IS	MediaStoredImage	1	PrivateTag
+(0025,"SVISION",08)	IS	ImageState	1	PrivateTag
+(0025,"SVISION",20)	LO	SourceImageFile	1	PrivateTag
+(0025,"SVISION",21)	UI	Unknown	1	PrivateTag
+(0027,"SVISION",00)	IS	NumberOfSeries	1	PrivateTag
+(0027,"SVISION",01)	IS	NumberOfStudies	1	PrivateTag
+(0027,"SVISION",10)	DT	OldestSeries	1	PrivateTag
+(0027,"SVISION",11)	DT	NewestSeries	1	PrivateTag
+(0027,"SVISION",12)	DT	OldestStudy	1	PrivateTag
+(0027,"SVISION",13)	DT	NewestStudy	1	PrivateTag
+
+(0009,"TOSHIBA_MEC_1.0",01)	LT	Unknown	1	PrivateTag
+(0009,"TOSHIBA_MEC_1.0",02)	US	Unknown	1-n	PrivateTag
+(0009,"TOSHIBA_MEC_1.0",03)	US	Unknown	1-n	PrivateTag
+(0009,"TOSHIBA_MEC_1.0",04)	US	Unknown	1-n	PrivateTag
+(0011,"TOSHIBA_MEC_1.0",01)	LT	Unknown	1	PrivateTag
+(0011,"TOSHIBA_MEC_1.0",02)	US	Unknown	1-n	PrivateTag
+(0019,"TOSHIBA_MEC_1.0",01)	US	Unknown	1-n	PrivateTag
+(0019,"TOSHIBA_MEC_1.0",02)	US	Unknown	1-n	PrivateTag
+(0021,"TOSHIBA_MEC_1.0",01)	US	Unknown	1-n	PrivateTag
+(0021,"TOSHIBA_MEC_1.0",02)	US	Unknown	1-n	PrivateTag
+(0021,"TOSHIBA_MEC_1.0",03)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_1.0",01)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_1.0",02)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_1.0",03)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_1.0",10)	US	Unknown	1-n	PrivateTag
+
+(0019,"TOSHIBA_MEC_CT_1.0",01)	IS	Unknown	1	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",02)	IS	Unknown	1	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",03)	US	Unknown	1-n	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",04)	LT	Unknown	1	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",05)	LT	Unknown	1	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",06)	US	Unknown	1-n	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",07)	US	Unknown	1-n	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",08)	LT	OrientationHeadFeet	1	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",09)	LT	ViewDirection	1	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",0a)	LT	OrientationSupineProne	1	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",0b)	DS	Unknown	1	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",0c)	US	Unknown	1-n	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",0d)	TM	Time	1	PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",0e)	DS	Unknown	1	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",01)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",02)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",03)	IS	Unknown	1	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",04)	IS	Unknown	1	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",05)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",07)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",08)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",09)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",0a)	LT	Unknown	1	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",0b)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",0c)	US	Unknown	1-n	PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",0d)	US	Unknown	1-n	PrivateTag
+#
+# end of private.dic
+#
diff --git a/Resources/Patches/dcmtk.txt b/Resources/Patches/dcmtk.txt
index 851fa4e..f4c161b 100644
--- a/Resources/Patches/dcmtk.txt
+++ b/Resources/Patches/dcmtk.txt
@@ -1 +1,10 @@
+Generate some patch
+===================
+
 diff -urEb dcmtk-3.6.0.orig/ dcmtk-3.6.0
+
+
+For "dcmtk-3.6.1-private.dic"
+=============================
+
+# cp ../../ThirdPartyDownloads/dcmtk-3.6.1_20160216/dcmdata/data/private.dic dcmtk-3.6.1-private.dic
diff --git a/Resources/Samples/Python/ArchiveStudiesInTimeRange.py b/Resources/Samples/Python/ArchiveStudiesInTimeRange.py
index 0da7a21..986a286 100755
--- a/Resources/Samples/Python/ArchiveStudiesInTimeRange.py
+++ b/Resources/Samples/Python/ArchiveStudiesInTimeRange.py
@@ -49,6 +49,12 @@ TARGET = sys.argv[4]
 CheckIsDate(START)
 CheckIsDate(END)
 
+def GetTag(tags, key):
+    if key in tags:
+        return tags[key]
+    else:
+        return 'No%s' % key
+
 # Loop over the studies
 for studyId in RestToolbox.DoGet('%s/studies' % URL):
     # Retrieve the DICOM tags of the current study
@@ -61,13 +67,13 @@ for studyId in RestToolbox.DoGet('%s/studies' % URL):
     studyDate = study['StudyDate'][:8]
     if studyDate >= START and studyDate <= END:
         # Create a filename
-        filename = '%s - %s %s - %s.zip' % (study['StudyDate'],
-                                            patient['PatientID'],
-                                            patient['PatientName'],
-                                            study['StudyDescription'])
+        filename = '%s - %s %s - %s.zip' % (GetTag(study, 'StudyDate'),
+                                            GetTag(patient, 'PatientID'),
+                                            GetTag(patient, 'PatientName'),
+                                            GetTag(study, 'StudyDescription'))
 
         # Remove any non-ASCII character in the filename
-        filename = filename.encode('ascii', errors = 'replace')
+        filename = filename.encode('ascii', errors = 'replace').translate(None, r"'\/:*?\"<>|!=").strip()
 
         # Download the ZIP archive of the study
         print('Downloading %s' % filename)
diff --git a/Resources/Samples/Python/AutoClassify.py b/Resources/Samples/Python/AutoClassify.py
index 1efd731..47922dd 100755
--- a/Resources/Samples/Python/AutoClassify.py
+++ b/Resources/Samples/Python/AutoClassify.py
@@ -45,7 +45,7 @@ parser.set_defaults(remove = False)
 
 
 def FixPath(p):
-    return p.encode('ascii', 'ignore').strip().decode()
+    return p.encode('ascii', errors = 'replace').translate(None, r"'\/:*?\"<>|!=").strip()
 
 def GetTag(resource, tag):
     if ('MainDicomTags' in resource and
@@ -110,13 +110,17 @@ while True:
         if change['ChangeType'] == 'NewInstance':
             try:
                 ClassifyInstance(change['ID'])
+
+                # If requested, remove the instance once it has been
+                # properly handled by "ClassifyInstance()". Thanks to
+                # the "try/except" block, the instance is not removed
+                # if the "ClassifyInstance()" function fails.
+                if args.remove:
+                    RestToolbox.DoDelete('%s/instances/%s' % (URL, change['ID']))
+
             except:
                 print('Unable to write instance %s to the disk' % change['ID'])
 
-            # If requested, remove the instance once it has been copied
-            if args.remove:
-                RestToolbox.DoDelete('%s/instances/%s' % (URL, change['ID']))
-
     current = r['Last']
 
     if r['Done']:
diff --git a/Resources/Samples/Python/DownloadAnonymized.py b/Resources/Samples/Python/DownloadAnonymized.py
index 721721e..4674af3 100755
--- a/Resources/Samples/Python/DownloadAnonymized.py
+++ b/Resources/Samples/Python/DownloadAnonymized.py
@@ -44,6 +44,5 @@ for patient in RestToolbox.DoGet('%s/patients' % URL):
         # Trigger the download
         print('Downloading %s' % name)
         zipContent = RestToolbox.DoGet('%s/patients/%s/archive' % (URL, patient))
-        f = open(os.path.join('/tmp', name + '.zip'), 'wb')
-        f.write(zipContent)
-        f.close()
+        with open(os.path.join('/tmp', name + '.zip'), 'wb') as f:
+            f.write(zipContent)
diff --git a/Resources/Samples/Tools/CMakeLists.txt b/Resources/Samples/Tools/CMakeLists.txt
index ce4cb36..c426f5e 100644
--- a/Resources/Samples/Tools/CMakeLists.txt
+++ b/Resources/Samples/Tools/CMakeLists.txt
@@ -22,12 +22,20 @@ include(${ORTHANC_ROOT}/Resources/CMake/BoostConfiguration.cmake)
 include(${ORTHANC_ROOT}/Resources/CMake/ZlibConfiguration.cmake)
 include(${ORTHANC_ROOT}/Resources/CMake/JsonCppConfiguration.cmake)
 
+add_definitions(
+  -DORTHANC_ENABLE_BASE64=0
+  -DORTHANC_ENABLE_MD5=0
+  -DORTHANC_ENABLE_PUGIXML=0
+  -DORTHANC_ENABLE_LOGGING=0
+  -DORTHANC_SANDBOXED=0
+  )
+
 add_library(CommonLibraries
   ${BOOST_SOURCES}
   ${JSONCPP_SOURCES}
   ${ORTHANC_ROOT}/Core/Enumerations.cpp
+  ${ORTHANC_ROOT}/Core/SystemToolbox.cpp
   ${ORTHANC_ROOT}/Core/Toolbox.cpp
-  ${ORTHANC_ROOT}/Core/Uuid.cpp
   ${ORTHANC_ROOT}/Resources/ThirdParty/md5/md5.c
   ${ORTHANC_ROOT}/Resources/ThirdParty/base64/base64.cpp
   )
diff --git a/Resources/Samples/Tools/RecoverCompressedFile.cpp b/Resources/Samples/Tools/RecoverCompressedFile.cpp
index b99e4e3..663ec72 100644
--- a/Resources/Samples/Tools/RecoverCompressedFile.cpp
+++ b/Resources/Samples/Tools/RecoverCompressedFile.cpp
@@ -19,7 +19,7 @@
 
 
 #include "../../../Core/Compression/ZlibCompressor.h"
-#include "../../../Core/Toolbox.h"
+#include "../../../Core/SystemToolbox.h"
 #include "../../../Core/OrthancException.h"
 
 #include <stdio.h>
@@ -40,7 +40,7 @@ int main(int argc, const char* argv[])
     fflush(stderr);
 
     std::string content;
-    Orthanc::Toolbox::ReadFile(content, argv[1]);
+    Orthanc::SystemToolbox::ReadFile(content, argv[1]);
 
     fprintf(stderr, "Decompressing the content of the file...\n");
     fflush(stderr);
@@ -56,7 +56,7 @@ int main(int argc, const char* argv[])
 
     if (argc == 3)
     {
-      Orthanc::Toolbox::WriteFile(uncompressed, argv[2]);
+      Orthanc::SystemToolbox::WriteFile(uncompressed, argv[2]);
     }
     else
     {
diff --git a/Resources/Samples/WebApplications/DrawingDicomizer.js b/Resources/Samples/WebApplications/DrawingDicomizer.js
index 2b80e52..93be150 100644
--- a/Resources/Samples/WebApplications/DrawingDicomizer.js
+++ b/Resources/Samples/WebApplications/DrawingDicomizer.js
@@ -58,7 +58,7 @@ var server = http.createServer(function(req, response) {
         toolbox.ServeFile('DrawingDicomizer/orthanc.js', response);
       }
       else if (req.url == '/jquery.js') {
-        toolbox.ServeFile('../../../OrthancExplorer/libs/jquery-1.7.2.min.js', response);
+        toolbox.ServeFile('../../../OrthancExplorer/libs/jquery.min.js', response);
       }
       else if (req.url.startsWith('/orthanc')) {
         toolbox.ForwardGetRequest(orthanc, req.url.substr(8), response);
@@ -96,4 +96,6 @@ var server = http.createServer(function(req, response) {
   }
 });
 
+
+console.log('The demo is running at http://localhost:' + port + '/');
 server.listen(port);
diff --git a/Resources/ThirdParty/VisualStudio/stdint.h b/Resources/ThirdParty/VisualStudio/stdint.h
index 59d0673..4fe0ef9 100644
--- a/Resources/ThirdParty/VisualStudio/stdint.h
+++ b/Resources/ThirdParty/VisualStudio/stdint.h
@@ -1,247 +1,259 @@
-// ISO C9x  compliant stdint.h for Microsoft Visual Studio
-// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
-// 
-//  Copyright (c) 2006-2008 Alexander Chemeris
-// 
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-// 
-//   1. Redistributions of source code must retain the above copyright notice,
-//      this list of conditions and the following disclaimer.
-// 
-//   2. 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.
-// 
-//   3. The name of the author may be used to endorse or promote products
-//      derived from this software without specific prior written permission.
-// 
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
-// 
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef _MSC_VER // [
-#error "Use this header only with Microsoft Visual C++ compilers!"
-#endif // _MSC_VER ]
-
-#ifndef _MSC_STDINT_H_ // [
-#define _MSC_STDINT_H_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif
-
-#include <limits.h>
-
-// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
-// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
-// or compiler give many errors like this:
-//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
-#ifdef __cplusplus
-extern "C" {
-#endif
-#  include <wchar.h>
-#ifdef __cplusplus
-}
-#endif
-
-// Define _W64 macros to mark types changing their size, like intptr_t.
-#ifndef _W64
-#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
-#     define _W64 __w64
-#  else
-#     define _W64
-#  endif
-#endif
-
-
-// 7.18.1 Integer types
-
-// 7.18.1.1 Exact-width integer types
-
-// Visual Studio 6 and Embedded Visual C++ 4 doesn't
-// realize that, e.g. char has the same size as __int8
-// so we give up on __intX for them.
-#if (_MSC_VER < 1300)
-   typedef signed char       int8_t;
-   typedef signed short      int16_t;
-   typedef signed int        int32_t;
-   typedef unsigned char     uint8_t;
-   typedef unsigned short    uint16_t;
-   typedef unsigned int      uint32_t;
-#else
-   typedef signed __int8     int8_t;
-   typedef signed __int16    int16_t;
-   typedef signed __int32    int32_t;
-   typedef unsigned __int8   uint8_t;
-   typedef unsigned __int16  uint16_t;
-   typedef unsigned __int32  uint32_t;
-#endif
-typedef signed __int64       int64_t;
-typedef unsigned __int64     uint64_t;
-
-
-// 7.18.1.2 Minimum-width integer types
-typedef int8_t    int_least8_t;
-typedef int16_t   int_least16_t;
-typedef int32_t   int_least32_t;
-typedef int64_t   int_least64_t;
-typedef uint8_t   uint_least8_t;
-typedef uint16_t  uint_least16_t;
-typedef uint32_t  uint_least32_t;
-typedef uint64_t  uint_least64_t;
-
-// 7.18.1.3 Fastest minimum-width integer types
-typedef int8_t    int_fast8_t;
-typedef int16_t   int_fast16_t;
-typedef int32_t   int_fast32_t;
-typedef int64_t   int_fast64_t;
-typedef uint8_t   uint_fast8_t;
-typedef uint16_t  uint_fast16_t;
-typedef uint32_t  uint_fast32_t;
-typedef uint64_t  uint_fast64_t;
-
-// 7.18.1.4 Integer types capable of holding object pointers
-#ifdef _WIN64 // [
-   typedef signed __int64    intptr_t;
-   typedef unsigned __int64  uintptr_t;
-#else // _WIN64 ][
-   typedef _W64 signed int   intptr_t;
-   typedef _W64 unsigned int uintptr_t;
-#endif // _WIN64 ]
-
-// 7.18.1.5 Greatest-width integer types
-typedef int64_t   intmax_t;
-typedef uint64_t  uintmax_t;
-
-
-// 7.18.2 Limits of specified-width integer types
-
-#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259
-
-// 7.18.2.1 Limits of exact-width integer types
-#define INT8_MIN     ((int8_t)_I8_MIN)
-#define INT8_MAX     _I8_MAX
-#define INT16_MIN    ((int16_t)_I16_MIN)
-#define INT16_MAX    _I16_MAX
-#define INT32_MIN    ((int32_t)_I32_MIN)
-#define INT32_MAX    _I32_MAX
-#define INT64_MIN    ((int64_t)_I64_MIN)
-#define INT64_MAX    _I64_MAX
-#define UINT8_MAX    _UI8_MAX
-#define UINT16_MAX   _UI16_MAX
-#define UINT32_MAX   _UI32_MAX
-#define UINT64_MAX   _UI64_MAX
-
-// 7.18.2.2 Limits of minimum-width integer types
-#define INT_LEAST8_MIN    INT8_MIN
-#define INT_LEAST8_MAX    INT8_MAX
-#define INT_LEAST16_MIN   INT16_MIN
-#define INT_LEAST16_MAX   INT16_MAX
-#define INT_LEAST32_MIN   INT32_MIN
-#define INT_LEAST32_MAX   INT32_MAX
-#define INT_LEAST64_MIN   INT64_MIN
-#define INT_LEAST64_MAX   INT64_MAX
-#define UINT_LEAST8_MAX   UINT8_MAX
-#define UINT_LEAST16_MAX  UINT16_MAX
-#define UINT_LEAST32_MAX  UINT32_MAX
-#define UINT_LEAST64_MAX  UINT64_MAX
-
-// 7.18.2.3 Limits of fastest minimum-width integer types
-#define INT_FAST8_MIN    INT8_MIN
-#define INT_FAST8_MAX    INT8_MAX
-#define INT_FAST16_MIN   INT16_MIN
-#define INT_FAST16_MAX   INT16_MAX
-#define INT_FAST32_MIN   INT32_MIN
-#define INT_FAST32_MAX   INT32_MAX
-#define INT_FAST64_MIN   INT64_MIN
-#define INT_FAST64_MAX   INT64_MAX
-#define UINT_FAST8_MAX   UINT8_MAX
-#define UINT_FAST16_MAX  UINT16_MAX
-#define UINT_FAST32_MAX  UINT32_MAX
-#define UINT_FAST64_MAX  UINT64_MAX
-
-// 7.18.2.4 Limits of integer types capable of holding object pointers
-#ifdef _WIN64 // [
-#  define INTPTR_MIN   INT64_MIN
-#  define INTPTR_MAX   INT64_MAX
-#  define UINTPTR_MAX  UINT64_MAX
-#else // _WIN64 ][
-#  define INTPTR_MIN   INT32_MIN
-#  define INTPTR_MAX   INT32_MAX
-#  define UINTPTR_MAX  UINT32_MAX
-#endif // _WIN64 ]
-
-// 7.18.2.5 Limits of greatest-width integer types
-#define INTMAX_MIN   INT64_MIN
-#define INTMAX_MAX   INT64_MAX
-#define UINTMAX_MAX  UINT64_MAX
-
-// 7.18.3 Limits of other integer types
-
-#ifdef _WIN64 // [
-#  define PTRDIFF_MIN  _I64_MIN
-#  define PTRDIFF_MAX  _I64_MAX
-#else  // _WIN64 ][
-#  define PTRDIFF_MIN  _I32_MIN
-#  define PTRDIFF_MAX  _I32_MAX
-#endif  // _WIN64 ]
-
-#define SIG_ATOMIC_MIN  INT_MIN
-#define SIG_ATOMIC_MAX  INT_MAX
-
-#ifndef SIZE_MAX // [
-#  ifdef _WIN64 // [
-#     define SIZE_MAX  _UI64_MAX
-#  else // _WIN64 ][
-#     define SIZE_MAX  _UI32_MAX
-#  endif // _WIN64 ]
-#endif // SIZE_MAX ]
-
-// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
-#ifndef WCHAR_MIN // [
-#  define WCHAR_MIN  0
-#endif  // WCHAR_MIN ]
-#ifndef WCHAR_MAX // [
-#  define WCHAR_MAX  _UI16_MAX
-#endif  // WCHAR_MAX ]
-
-#define WINT_MIN  0
-#define WINT_MAX  _UI16_MAX
-
-#endif // __STDC_LIMIT_MACROS ]
-
-
-// 7.18.4 Limits of other integer types
-
-#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
-
-// 7.18.4.1 Macros for minimum-width integer constants
-
-#define INT8_C(val)  val##i8
-#define INT16_C(val) val##i16
-#define INT32_C(val) val##i32
-#define INT64_C(val) val##i64
-
-#define UINT8_C(val)  val##ui8
-#define UINT16_C(val) val##ui16
-#define UINT32_C(val) val##ui32
-#define UINT64_C(val) val##ui64
-
-// 7.18.4.2 Macros for greatest-width integer constants
-#define INTMAX_C   INT64_C
-#define UINTMAX_C  UINT64_C
-
-#endif // __STDC_CONSTANT_MACROS ]
-
-
-#endif // _MSC_STDINT_H_ ]
+// ISO C9x  compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
+// 
+//  Copyright (c) 2006-2013 Alexander Chemeris
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+// 
+//   2. 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.
+// 
+//   3. Neither the name of the product 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 AUTHOR ``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 AUTHOR 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.
+// 
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#if _MSC_VER >= 1600 // [
+#include <stdint.h>
+#else // ] _MSC_VER >= 1600 [
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+#  include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+#     define _W64 __w64
+#  else
+#     define _W64
+#  endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+   typedef signed char       int8_t;
+   typedef signed short      int16_t;
+   typedef signed int        int32_t;
+   typedef unsigned char     uint8_t;
+   typedef unsigned short    uint16_t;
+   typedef unsigned int      uint32_t;
+#else
+   typedef signed __int8     int8_t;
+   typedef signed __int16    int16_t;
+   typedef signed __int32    int32_t;
+   typedef unsigned __int8   uint8_t;
+   typedef unsigned __int16  uint16_t;
+   typedef unsigned __int32  uint32_t;
+#endif
+typedef signed __int64       int64_t;
+typedef unsigned __int64     uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t    int_least8_t;
+typedef int16_t   int_least16_t;
+typedef int32_t   int_least32_t;
+typedef int64_t   int_least64_t;
+typedef uint8_t   uint_least8_t;
+typedef uint16_t  uint_least16_t;
+typedef uint32_t  uint_least32_t;
+typedef uint64_t  uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t    int_fast8_t;
+typedef int16_t   int_fast16_t;
+typedef int32_t   int_fast32_t;
+typedef int64_t   int_fast64_t;
+typedef uint8_t   uint_fast8_t;
+typedef uint16_t  uint_fast16_t;
+typedef uint32_t  uint_fast32_t;
+typedef uint64_t  uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+   typedef signed __int64    intptr_t;
+   typedef unsigned __int64  uintptr_t;
+#else // _WIN64 ][
+   typedef _W64 signed int   intptr_t;
+   typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t   intmax_t;
+typedef uint64_t  uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN     ((int8_t)_I8_MIN)
+#define INT8_MAX     _I8_MAX
+#define INT16_MIN    ((int16_t)_I16_MIN)
+#define INT16_MAX    _I16_MAX
+#define INT32_MIN    ((int32_t)_I32_MIN)
+#define INT32_MAX    _I32_MAX
+#define INT64_MIN    ((int64_t)_I64_MIN)
+#define INT64_MAX    _I64_MAX
+#define UINT8_MAX    _UI8_MAX
+#define UINT16_MAX   _UI16_MAX
+#define UINT32_MAX   _UI32_MAX
+#define UINT64_MAX   _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN    INT8_MIN
+#define INT_LEAST8_MAX    INT8_MAX
+#define INT_LEAST16_MIN   INT16_MIN
+#define INT_LEAST16_MAX   INT16_MAX
+#define INT_LEAST32_MIN   INT32_MIN
+#define INT_LEAST32_MAX   INT32_MAX
+#define INT_LEAST64_MIN   INT64_MIN
+#define INT_LEAST64_MAX   INT64_MAX
+#define UINT_LEAST8_MAX   UINT8_MAX
+#define UINT_LEAST16_MAX  UINT16_MAX
+#define UINT_LEAST32_MAX  UINT32_MAX
+#define UINT_LEAST64_MAX  UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN    INT8_MIN
+#define INT_FAST8_MAX    INT8_MAX
+#define INT_FAST16_MIN   INT16_MIN
+#define INT_FAST16_MAX   INT16_MAX
+#define INT_FAST32_MIN   INT32_MIN
+#define INT_FAST32_MAX   INT32_MAX
+#define INT_FAST64_MIN   INT64_MIN
+#define INT_FAST64_MAX   INT64_MAX
+#define UINT_FAST8_MAX   UINT8_MAX
+#define UINT_FAST16_MAX  UINT16_MAX
+#define UINT_FAST32_MAX  UINT32_MAX
+#define UINT_FAST64_MAX  UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+#  define INTPTR_MIN   INT64_MIN
+#  define INTPTR_MAX   INT64_MAX
+#  define UINTPTR_MAX  UINT64_MAX
+#else // _WIN64 ][
+#  define INTPTR_MIN   INT32_MIN
+#  define INTPTR_MAX   INT32_MAX
+#  define UINTPTR_MAX  UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN   INT64_MIN
+#define INTMAX_MAX   INT64_MAX
+#define UINTMAX_MAX  UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+#  define PTRDIFF_MIN  _I64_MIN
+#  define PTRDIFF_MAX  _I64_MAX
+#else  // _WIN64 ][
+#  define PTRDIFF_MIN  _I32_MIN
+#  define PTRDIFF_MAX  _I32_MAX
+#endif  // _WIN64 ]
+
+#define SIG_ATOMIC_MIN  INT_MIN
+#define SIG_ATOMIC_MAX  INT_MAX
+
+#ifndef SIZE_MAX // [
+#  ifdef _WIN64 // [
+#     define SIZE_MAX  _UI64_MAX
+#  else // _WIN64 ][
+#     define SIZE_MAX  _UI32_MAX
+#  endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+#  define WCHAR_MIN  0
+#endif  // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+#  define WCHAR_MAX  _UI16_MAX
+#endif  // WCHAR_MAX ]
+
+#define WINT_MIN  0
+#define WINT_MAX  _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val)  val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val)  val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C //   [
+#  define INTMAX_C   INT64_C
+#endif // INTMAX_C    ]
+#ifndef UINTMAX_C //  [
+#  define UINTMAX_C  UINT64_C
+#endif // UINTMAX_C   ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#endif // _MSC_VER >= 1600 ]
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/Resources/ThirdParty/base64/base64.cpp b/Resources/ThirdParty/base64/base64.cpp
index 621c81c..33289c9 100644
--- a/Resources/ThirdParty/base64/base64.cpp
+++ b/Resources/ThirdParty/base64/base64.cpp
@@ -1,128 +1,128 @@
-/* 
-   base64.cpp and base64.h
-
-   Copyright (C) 2004-2008 Ren� Nyffenegger
-
-   This source code is provided 'as-is', without any express or implied
-   warranty. In no event will the author be held liable for any damages
-   arising from the use of this software.
-
-   Permission is granted to anyone to use this software for any purpose,
-   including commercial applications, and to alter it and redistribute it
-   freely, subject to the following restrictions:
-
-   1. The origin of this source code must not be misrepresented; you must not
-      claim that you wrote the original source code. If you use this source code
-      in a product, an acknowledgment in the product documentation would be
-      appreciated but is not required.
-
-   2. Altered source versions must be plainly marked as such, and must not be
-      misrepresented as being the original source code.
-
-   3. This notice may not be removed or altered from any source distribution.
-
-   Ren� Nyffenegger rene.nyffenegger at adp-gmbh.ch
-
-*/
-
-#include "base64.h"
-#include <string.h>
-
-static const std::string base64_chars = 
-             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-             "abcdefghijklmnopqrstuvwxyz"
-             "0123456789+/";
-
-
-static inline bool is_base64(unsigned char c) {
-  return (isalnum(c) || (c == '+') || (c == '/'));
-}
-
-std::string base64_encode(const std::string& stringToEncode) 
-{
-  const unsigned char* bytes_to_encode = reinterpret_cast<const unsigned char*>
-    (stringToEncode.size() > 0 ? &stringToEncode[0] : NULL);
-  unsigned int in_len = stringToEncode.size();
-  
-  std::string ret;
-  int i = 0;
-  int j = 0;
-  unsigned char char_array_3[3];
-  unsigned char char_array_4[4];
-
-  while (in_len--) {
-    char_array_3[i++] = *(bytes_to_encode++);
-    if (i == 3) {
-      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
-      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
-      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
-      char_array_4[3] = char_array_3[2] & 0x3f;
-
-      for(i = 0; (i <4) ; i++)
-        ret += base64_chars[char_array_4[i]];
-      i = 0;
-    }
-  }
-
-  if (i)
-  {
-    for(j = i; j < 3; j++)
-      char_array_3[j] = '\0';
-
-    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
-    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
-    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
-    char_array_4[3] = char_array_3[2] & 0x3f;
-
-    for (j = 0; (j < i + 1); j++)
-      ret += base64_chars[char_array_4[j]];
-
-    while((i++ < 3))
-      ret += '=';
-
-  }
-
-  return ret;
-}
-
-
-std::string base64_decode(const std::string& encoded_string) {
-  int in_len = encoded_string.size();
-  int i = 0;
-  int j = 0;
-  int in_ = 0;
-  unsigned char char_array_4[4], char_array_3[3];
-  std::string ret;
-
-  while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
-    char_array_4[i++] = encoded_string[in_]; in_++;
-    if (i ==4) {
-      for (i = 0; i <4; i++)
-        char_array_4[i] = base64_chars.find(char_array_4[i]);
-
-      char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
-      char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
-      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
-
-      for (i = 0; (i < 3); i++)
-        ret += char_array_3[i];
-      i = 0;
-    }
-  }
-
-  if (i) {
-    for (j = i; j <4; j++)
-      char_array_4[j] = 0;
-
-    for (j = 0; j <4; j++)
-      char_array_4[j] = base64_chars.find(char_array_4[j]);
-
-    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
-    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
-    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
-
-    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
-  }
-
-  return ret;
-}
+/* 
+   base64.cpp and base64.h
+
+   Copyright (C) 2004-2008 Ren� Nyffenegger
+
+   This source code is provided 'as-is', without any express or implied
+   warranty. In no event will the author be held liable for any damages
+   arising from the use of this software.
+
+   Permission is granted to anyone to use this software for any purpose,
+   including commercial applications, and to alter it and redistribute it
+   freely, subject to the following restrictions:
+
+   1. The origin of this source code must not be misrepresented; you must not
+      claim that you wrote the original source code. If you use this source code
+      in a product, an acknowledgment in the product documentation would be
+      appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+      misrepresented as being the original source code.
+
+   3. This notice may not be removed or altered from any source distribution.
+
+   Ren� Nyffenegger rene.nyffenegger at adp-gmbh.ch
+
+*/
+
+#include "base64.h"
+#include <string.h>
+
+static const std::string base64_chars = 
+             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+             "abcdefghijklmnopqrstuvwxyz"
+             "0123456789+/";
+
+
+static inline bool is_base64(unsigned char c) {
+  return (isalnum(c) || (c == '+') || (c == '/'));
+}
+
+std::string base64_encode(const std::string& stringToEncode) 
+{
+  const unsigned char* bytes_to_encode = reinterpret_cast<const unsigned char*>
+    (stringToEncode.size() > 0 ? &stringToEncode[0] : NULL);
+  unsigned int in_len = stringToEncode.size();
+  
+  std::string ret;
+  int i = 0;
+  int j = 0;
+  unsigned char char_array_3[3];
+  unsigned char char_array_4[4];
+
+  while (in_len--) {
+    char_array_3[i++] = *(bytes_to_encode++);
+    if (i == 3) {
+      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+      char_array_4[3] = char_array_3[2] & 0x3f;
+
+      for(i = 0; (i <4) ; i++)
+        ret += base64_chars[char_array_4[i]];
+      i = 0;
+    }
+  }
+
+  if (i)
+  {
+    for(j = i; j < 3; j++)
+      char_array_3[j] = '\0';
+
+    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+    char_array_4[3] = char_array_3[2] & 0x3f;
+
+    for (j = 0; (j < i + 1); j++)
+      ret += base64_chars[char_array_4[j]];
+
+    while((i++ < 3))
+      ret += '=';
+
+  }
+
+  return ret;
+}
+
+
+std::string base64_decode(const std::string& encoded_string) {
+  int in_len = encoded_string.size();
+  int i = 0;
+  int j = 0;
+  int in_ = 0;
+  unsigned char char_array_4[4], char_array_3[3];
+  std::string ret;
+
+  while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
+    char_array_4[i++] = encoded_string[in_]; in_++;
+    if (i ==4) {
+      for (i = 0; i <4; i++)
+        char_array_4[i] = base64_chars.find(char_array_4[i]);
+
+      char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+      char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+      for (i = 0; (i < 3); i++)
+        ret += char_array_3[i];
+      i = 0;
+    }
+  }
+
+  if (i) {
+    for (j = i; j <4; j++)
+      char_array_4[j] = 0;
+
+    for (j = 0; j <4; j++)
+      char_array_4[j] = base64_chars.find(char_array_4[j]);
+
+    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
+  }
+
+  return ret;
+}
diff --git a/Resources/ThirdParty/base64/base64.h b/Resources/ThirdParty/base64/base64.h
index acdaecd..5e62f1a 100644
--- a/Resources/ThirdParty/base64/base64.h
+++ b/Resources/ThirdParty/base64/base64.h
@@ -1,4 +1,4 @@
-#include <string>
-
-std::string base64_encode(const std::string& stringToEncode);
-std::string base64_decode(const std::string& s);
+#include <string>
+
+std::string base64_encode(const std::string& stringToEncode);
+std::string base64_decode(const std::string& s);
diff --git a/THANKS b/THANKS
deleted file mode 100644
index e6d96b6..0000000
--- a/THANKS
+++ /dev/null
@@ -1,65 +0,0 @@
-Orthanc - A Lightweight, RESTful DICOM Server
-=============================================
-
-Orthanc has originally been written by Sebastien Jodogne
-(cf. "AUTHORS" file). This file contains the list of the people that
-have further contributed to Orthanc by reporting problems, suggesting
-various improvements, or submitting actual code. Please help keep it
-complete and exempt or errors.
-
-
-Contributors
-------------
-
-* Cyril Paulus <cyril.paulus at student.ulg.ac.be>, for the build process
-  and suggestions about the REST API.
-* Will Ryder <will.ryder at sydney.edu.au>, for improvements with the
-  handling of series with temporal positions (fMRI and dynamic PET).
-* Ryan Walklin <ryanwalklin at gmail.com>, for Mac OS X build.
-* Peter Somlo <peter.somlo at gmail.com>, for ClearCanvas and JPEG support.
-* 12maksqwe at gmail.com, for fixing issue #8.
-* Julien Nabet, for various suggestions to improve the source code.
-* Karsten Hilbert <Karsten.Hilbert at gmx.net>, for in-depth testing.
-* Marek Swiecicki <mswiecicki at archimedic.pl>, for various suggestions
-  and sample DICOM files.
-* Chris Hafey <chafey at gmail.com>, for suggesting many features and
-  improvements, for a Windows service+installer with .NET/NSIS.
-* Manabu Tokunaga <manabu at lury.net>, for a Windows service with .NET.
-* Vincent Kersten <vincent1234567 at gmail.com>, for DICOMDIR in the GUI.
-* Emsy Chan <emlscs at yahoo.com>, for various contributions
-  and sample DICOM files.
-
-
-Thanks also to all the contributors active in our Google Group:
-https://groups.google.com/forum/#!forum/orthanc-users
-
-
-Debian/Ubuntu
--------------
-
-* Mathieu Malaterre <mathieu.malaterre at gmail.com>, for sponsoring Orthanc.
-* Andreas Tille <andreas at an3as.eu>, for help about packaging. 
-* Adam Conrad <adconrad at debian.org>, to improve support of big endianness.
-
-
-Fedora and Red Hat
-------------------
-
-* Mario Ceresa <mrceresa at gmail.com>, for help about packaging.
-
-
-FreeBSD
--------
-
-* Mikhail <mp39590 at gmail.com>, for FreeBSD packaging.
-
-
-Artwork
--------
-
-https://code.google.com/p/orthanc/wiki/Logos
-
-* Benjamin Golinvaux <golinvauxb at gmail.com>, for creating the official logo.
-* Jean-François Degbomont <jfdegbo at gmail.com>, for submitting a logo.
-* Martin Jolly <martin.jolly at gmail.com>, for submitting a logo.
-* Philippe Sepers <sepers.philippe at gmail.com>, for submitting a logo.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..7b2aa1c
--- /dev/null
+++ b/TODO
@@ -0,0 +1,152 @@
+=======================
+=== Orthanc Roadmap ===
+=======================
+
+The wishlist from Orthanc users is available on Trello:
+https://trello.com/b/gcn33tDM/orthanc-wishlist
+
+
+=======
+General
+=======
+
+* Configure an user-defined site UID root if generating DICOM UIDs
+  ("FromDcmtkBridge::GenerateUuid()")
+* Support "/preview" and "/matlab" for LUT color images
+* Improve handling of errors in the command queue:
+  https://groups.google.com/d/msg/orthanc-users/--njEbqcDDI/rBu8XL-Mm-cJ
+* Support partial file retrieval in Orthanc::HttpClient
+* Support retry counter in Orthanc::HttpClient
+
+
+========
+REST API
+========
+
+----------
+Short-term
+----------
+
+* Create multi-frame images with /tools/create-dicom (by adding a
+  "MultiFrame" flag to avoid creating a series)
+
+---------
+Long-term
+---------
+
+* Stick to the JSONapi or JAREST guidelines for a "v2" of the API:
+  https://groups.google.com/forum/#!msg/orthanc-users/Bag-SwEE9ZI/-w7QXI6p7-oJ
+  http://www.admiraalit.nl/jarest/
+
+
+=====
+DICOM
+=====
+
+----------
+Short-term
+----------
+
+* Support C-GET: 
+  http://dclunie.blogspot.be/2016/05/to-c-move-is-human-to-c-get-divine.html
+* Check Big Endian transfer syntax in ParsedDicomFile::EmbedImage and
+  DicomImageDecoder
+
+---------
+Long-term
+---------
+
+* Support DICOM TLS (cf. "--enable-tls" in storescp)
+* Support Storage Commitment:
+  https://groups.google.com/forum/#!msg/orthanc-users/VZOn8St65jw/s8kg_OHesj0J
+
+
+=======
+Plugins
+=======
+
+---
+SDK
+---
+
+* Image transcoding API
+* Add plugins for normalized operations (notably so as to support
+  Print SCU/SCP):
+  https://www.medicalconnections.co.uk/kb/DICOM_Print_Service
+
+----------------
+Ideas of plugins
+----------------
+
+* DICOM-RT primitives (RT-STRUCT, RT-PLAN, RT-DOSE)
+* Converter to/from NIfTI
+* MySQL database plugin
+* Decode JPEG2k with grok: https://github.com/GrokImageCompression/grok
+* Generate dynamic content using Lua:
+  https://groups.google.com/d/msg/orthanc-users/KompazkxRSs/5Rh03mzgDAAJ
+
+
+===
+Lua
+===
+
+* Configure HTTP headers from Lua (in HttpGet(), HttpPost(),
+  HttpPut(), HttpDelete(), RestApiGet(), RestApiPost(), RestApiPut()
+  and RestApiDelete().
+  https://groups.google.com/forum/#!msg/orthanc-users/WNnW187OILM/6XX_bm96BwAJ
+
+
+===========
+Performance
+===========
+
+
+============
+Orthanc Book
+============
+
+* Document Lua C-FIND filters (cf. "IncomingFindRequestFilter()")
+
+
+================
+Code refactoring
+================
+
+* Use Semaphore::Locker everywhere (instead of explicit
+  Release() and Acquire())
+* Avoid direct calls to FromDcmtkBridge (make most of its 
+  methods private), go through ParsedDicomFile wherever possible
+
+
+=================
+Platform-specific
+=================
+
+---------
+Packaging
+---------
+
+* CentOS and RHEL through EPEL:
+  http://fedoraproject.org/wiki/EPEL_Package_Maintainers
+
+------------------------
+Big-endian architectures
+------------------------
+
+* Check the generated 16bpp PNG images
+
+-----------------
+Microsoft Windows
+-----------------
+
+* Add compatibility with non-ASCII paths (Orthanc expresses its paths
+  as UTF-8 strings, but Windows expects them to be translated to the 
+  system locale)
+
+
+=====================
+External applications
+=====================
+
+* Create REST bindings with Slicer
+* Create REST bindings with Horos/OsiriX
diff --git a/UnitTestsSources/DicomMapTests.cpp b/UnitTestsSources/DicomMapTests.cpp
index d3a4474..34245a0 100644
--- a/UnitTestsSources/DicomMapTests.cpp
+++ b/UnitTestsSources/DicomMapTests.cpp
@@ -33,7 +33,6 @@
 #include "PrecompiledHeadersUnitTests.h"
 #include "gtest/gtest.h"
 
-#include "../Core/Uuid.h"
 #include "../Core/OrthancException.h"
 #include "../Core/DicomFormat/DicomMap.h"
 #include "../OrthancServer/FromDcmtkBridge.h"
@@ -204,7 +203,7 @@ static void TestModule(ResourceType level,
 
     if (!ok)
     {
-      std::cout << it->Format() << ": " << FromDcmtkBridge::GetName(*it)
+      std::cout << it->Format() << ": " << FromDcmtkBridge::GetTagName(*it, "")
                 << " not expected at level " << EnumerationToString(level) << std::endl;
     }
 
diff --git a/UnitTestsSources/FileStorageTests.cpp b/UnitTestsSources/FileStorageTests.cpp
index 6c9ef75..cabe267 100644
--- a/UnitTestsSources/FileStorageTests.cpp
+++ b/UnitTestsSources/FileStorageTests.cpp
@@ -42,7 +42,6 @@
 #include "../Core/Logging.h"
 #include "../Core/OrthancException.h"
 #include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
 #include "../OrthancServer/ServerIndex.h"
 
 using namespace Orthanc;
@@ -61,8 +60,8 @@ TEST(FilesystemStorage, Basic)
 {
   FilesystemStorage s("UnitTestsStorage");
 
-  std::string data = Toolbox::GenerateUuid();
-  std::string uid = Toolbox::GenerateUuid();
+  std::string data = SystemToolbox::GenerateUuid();
+  std::string uid = SystemToolbox::GenerateUuid();
   s.Create(uid.c_str(), &data[0], data.size(), FileContentType_Unknown);
   std::string d;
   s.Read(d, uid, FileContentType_Unknown);
@@ -76,8 +75,8 @@ TEST(FilesystemStorage, Basic2)
   FilesystemStorage s("UnitTestsStorage");
 
   std::vector<uint8_t> data;
-  StringToVector(data, Toolbox::GenerateUuid());
-  std::string uid = Toolbox::GenerateUuid();
+  StringToVector(data, SystemToolbox::GenerateUuid());
+  std::string uid = SystemToolbox::GenerateUuid();
   s.Create(uid.c_str(), &data[0], data.size(), FileContentType_Unknown);
   std::string d;
   s.Read(d, uid, FileContentType_Unknown);
@@ -94,8 +93,8 @@ TEST(FilesystemStorage, EndToEnd)
   std::list<std::string> u;
   for (unsigned int i = 0; i < 10; i++)
   {
-    std::string t = Toolbox::GenerateUuid();
-    std::string uid = Toolbox::GenerateUuid();
+    std::string t = SystemToolbox::GenerateUuid();
+    std::string uid = SystemToolbox::GenerateUuid();
     s.Create(uid.c_str(), &t[0], t.size(), FileContentType_Unknown);
     u.push_back(uid);
   }
diff --git a/UnitTestsSources/FromDcmtkTests.cpp b/UnitTestsSources/FromDcmtkTests.cpp
index f35bdda..939e057 100644
--- a/UnitTestsSources/FromDcmtkTests.cpp
+++ b/UnitTestsSources/FromDcmtkTests.cpp
@@ -44,7 +44,6 @@
 #include "../Core/Images/PngWriter.h"
 #include "../Core/Images/Image.h"
 #include "../Core/Images/ImageProcessing.h"
-#include "../Core/Uuid.h"
 #include "../Core/Endianness.h"
 #include "../Resources/EncodingTests.h"
 #include "../OrthancServer/DicomProtocol/DicomFindAnswers.h"
@@ -52,12 +51,13 @@
 #include "../Plugins/Engine/PluginsEnumerations.h"
 
 #include <dcmtk/dcmdata/dcelem.h>
+#include <dcmtk/dcmdata/dcdeftag.h>
 
 using namespace Orthanc;
 
 TEST(DicomFormat, Tag)
 {
-  ASSERT_EQ("PatientName", FromDcmtkBridge::GetName(DicomTag(0x0010, 0x0010)));
+  ASSERT_EQ("PatientName", FromDcmtkBridge::GetTagName(DicomTag(0x0010, 0x0010), ""));
 
   DicomTag t = FromDcmtkBridge::ParseTag("SeriesDescription");
   ASSERT_EQ(0x0008, t.GetGroup());
@@ -226,7 +226,7 @@ TEST(FromDcmtkBridge, Enumerations)
   Encoding e;
 
   ASSERT_FALSE(GetDicomEncoding(e, ""));
-  ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 6"));  ASSERT_EQ(Encoding_Utf8, e);
+  ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 6"));  ASSERT_EQ(Encoding_Ascii, e);
 
   // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#table_C.12-2
   ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 100"));  ASSERT_EQ(Encoding_Latin1, e);
@@ -242,7 +242,7 @@ TEST(FromDcmtkBridge, Enumerations)
   ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 166"));  ASSERT_EQ(Encoding_Thai, e);
 
   // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#table_C.12-3
-  ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 6"));    ASSERT_EQ(Encoding_Utf8, e);
+  ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 6"));    ASSERT_EQ(Encoding_Ascii, e);
   ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 100"));  ASSERT_EQ(Encoding_Latin1, e);
   ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 101"));  ASSERT_EQ(Encoding_Latin2, e);
   ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 109"));  ASSERT_EQ(Encoding_Latin3, e);
@@ -380,81 +380,85 @@ static void CreateSampleJson(Json::Value& a)
 }
 
 
-TEST(FromDcmtkBridge, FromJson)
+namespace Orthanc
 {
-  std::auto_ptr<DcmElement> element;
-
-  {
-    Json::Value a;
-    a = "Hello";
-    element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8));
-
-    Json::Value b;
-    FromDcmtkBridge::ToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
-    ASSERT_EQ("Hello", b["0010,0010"].asString());
-  }
-
+  // Namespace for the "FRIEND_TEST()" directive in "FromDcmtkBridge" to apply:
+  // https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#private-class-members
+  TEST(FromDcmtkBridge, FromJson)
   {
-    Json::Value a;
-    a = "Hello";
-    // Cannot assign a string to a sequence
-    ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, false, Encoding_Utf8)), OrthancException);
-  }
+    std::auto_ptr<DcmElement> element;
 
-  {
-    Json::Value a = Json::arrayValue;
-    a.append("Hello");
-    // Cannot assign an array to a string
-    ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8)), OrthancException);
-  }
+    {
+      Json::Value a;
+      a = "Hello";
+      element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8));
 
-  {
-    Json::Value a;
-    a = "data:application/octet-stream;base64,SGVsbG8=";  // echo -n "Hello" | base64
-    element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, true, Encoding_Utf8));
+      Json::Value b;
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+      ASSERT_EQ("Hello", b["0010,0010"].asString());
+    }
 
-    Json::Value b;
-    FromDcmtkBridge::ToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
-    ASSERT_EQ("Hello", b["0010,0010"].asString());
-  }
+    {
+      Json::Value a;
+      a = "Hello";
+      // Cannot assign a string to a sequence
+      ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, false, Encoding_Utf8)), OrthancException);
+    }
 
-  {
-    Json::Value a = Json::arrayValue;
-    CreateSampleJson(a);
-    element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, true, Encoding_Utf8));
+    {
+      Json::Value a = Json::arrayValue;
+      a.append("Hello");
+      // Cannot assign an array to a string
+      ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8)), OrthancException);
+    }
 
     {
+      Json::Value a;
+      a = "data:application/octet-stream;base64,SGVsbG8=";  // echo -n "Hello" | base64
+      element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, true, Encoding_Utf8));
+
       Json::Value b;
-      FromDcmtkBridge::ToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
-      ASSERT_EQ(Json::arrayValue, b["0008,1110"].type());
-      ASSERT_EQ(2u, b["0008,1110"].size());
-      
-      Json::Value::ArrayIndex i = (b["0008,1110"][0]["0010,0010"].asString() == "Hello") ? 0 : 1;
-
-      ASSERT_EQ(3u, b["0008,1110"][i].size());
-      ASSERT_EQ(2u, b["0008,1110"][1 - i].size());
-      ASSERT_EQ(b["0008,1110"][i]["0010,0010"].asString(), "Hello");
-      ASSERT_EQ(b["0008,1110"][i]["0010,0020"].asString(), "World");
-      ASSERT_EQ(b["0008,1110"][i]["0008,1030"].asString(), "Toto");
-      ASSERT_EQ(b["0008,1110"][1 - i]["0010,0010"].asString(), "Hello2");
-      ASSERT_EQ(b["0008,1110"][1 - i]["0010,0020"].asString(), "World2");
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+      ASSERT_EQ("Hello", b["0010,0010"].asString());
     }
 
     {
-      Json::Value b;
-      FromDcmtkBridge::ToJson(b, *element, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+      Json::Value a = Json::arrayValue;
+      CreateSampleJson(a);
+      element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, true, Encoding_Utf8));
+
+      {
+        Json::Value b;
+        FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+        ASSERT_EQ(Json::arrayValue, b["0008,1110"].type());
+        ASSERT_EQ(2u, b["0008,1110"].size());
+      
+        Json::Value::ArrayIndex i = (b["0008,1110"][0]["0010,0010"].asString() == "Hello") ? 0 : 1;
+
+        ASSERT_EQ(3u, b["0008,1110"][i].size());
+        ASSERT_EQ(2u, b["0008,1110"][1 - i].size());
+        ASSERT_EQ(b["0008,1110"][i]["0010,0010"].asString(), "Hello");
+        ASSERT_EQ(b["0008,1110"][i]["0010,0020"].asString(), "World");
+        ASSERT_EQ(b["0008,1110"][i]["0008,1030"].asString(), "Toto");
+        ASSERT_EQ(b["0008,1110"][1 - i]["0010,0010"].asString(), "Hello2");
+        ASSERT_EQ(b["0008,1110"][1 - i]["0010,0020"].asString(), "World2");
+      }
+
+      {
+        Json::Value b;
+        FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0, Encoding_Ascii);
 
-      Json::Value c;
-      Toolbox::SimplifyTags(c, b, DicomToJsonFormat_Human);
+        Json::Value c;
+        ServerToolbox::SimplifyTags(c, b, DicomToJsonFormat_Human);
 
-      a[1]["PatientName"] = "Hello2";  // To remove the Data URI Scheme encoding
-      ASSERT_EQ(0, c["ReferencedStudySequence"].compare(a));
+        a[1]["PatientName"] = "Hello2";  // To remove the Data URI Scheme encoding
+        ASSERT_EQ(0, c["ReferencedStudySequence"].compare(a));
+      }
     }
   }
 }
 
 
-
 TEST(ParsedDicomFile, InsertReplaceStrings)
 {
   ParsedDicomFile f(true);
@@ -465,6 +469,7 @@ TEST(ParsedDicomFile, InsertReplaceStrings)
   f.ReplacePlainString(DICOM_TAG_SOP_CLASS_UID, "Tata");  // (**)
 
   std::string s;
+  ASSERT_FALSE(f.LookupTransferSyntax(s));
 
   ASSERT_THROW(f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession"),
                          false, DicomReplaceMode_ThrowIfAbsent), OrthancException);
@@ -522,10 +527,10 @@ TEST(ParsedDicomFile, InsertReplaceJson)
 
   {
     Json::Value b;
-    f.ToJson(b, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0);
+    f.DatasetToJson(b, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0);
 
     Json::Value c;
-    Toolbox::SimplifyTags(c, b, DicomToJsonFormat_Human);
+    ServerToolbox::SimplifyTags(c, b, DicomToJsonFormat_Human);
 
     ASSERT_EQ(0, c["ReferencedPatientSequence"].compare(a));
     ASSERT_NE(0, c["ReferencedStudySequence"].compare(a));  // Because Data URI Scheme decoding was enabled
@@ -567,7 +572,7 @@ TEST(ParsedDicomFile, JsonEncoding)
       f.Replace(DICOM_TAG_PATIENT_NAME, s, false, DicomReplaceMode_InsertIfAbsent);
 
       Json::Value v;
-      f.ToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+      f.DatasetToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
       ASSERT_EQ(v["PatientName"].asString(), std::string(testEncodingsExpected[i]));
     }
   }
@@ -576,8 +581,8 @@ TEST(ParsedDicomFile, JsonEncoding)
 
 TEST(ParsedDicomFile, ToJsonFlags1)
 {
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7053, 0x1000), ValueRepresentation_PersonName, "MyPrivateTag", 1, 1);
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PersonName, "Declared public tag", 1, 1);
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7053, 0x1000), ValueRepresentation_PersonName, "MyPrivateTag", 1, 1, "");
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PersonName, "Declared public tag", 1, 1, "");
 
   ParsedDicomFile f(true);
   f.Insert(DicomTag(0x7050, 0x1000), "Some public tag", false);  // Even group => public tag
@@ -585,7 +590,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
   f.Insert(DicomTag(0x7053, 0x1000), "Some private tag", false);  // Odd group => private tag
 
   Json::Value v;
-  f.ToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(6u, v.getMemberNames().size());
   ASSERT_FALSE(v.isMember("7052,1000"));
@@ -594,7 +599,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
   ASSERT_EQ(Json::stringValue, v["7050,1000"].type());
   ASSERT_EQ("Some public tag", v["7050,1000"].asString());
 
-  f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(7u, v.getMemberNames().size());
   ASSERT_FALSE(v.isMember("7052,1000"));
@@ -603,7 +608,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
   ASSERT_EQ("Some public tag", v["7050,1000"].asString());
   ASSERT_EQ(Json::nullValue, v["7053,1000"].type());
 
-  f.ToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludePrivateTags, 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludePrivateTags, 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(7u, v.getMemberNames().size());
   ASSERT_FALSE(v.isMember("7052,1000"));
@@ -616,7 +621,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
   ASSERT_EQ("application/octet-stream", mime);
   ASSERT_EQ("Some private tag", content);
 
-  f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(7u, v.getMemberNames().size());
   ASSERT_TRUE(v.isMember("7050,1000"));
@@ -625,7 +630,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
   ASSERT_EQ("Some public tag", v["7050,1000"].asString());
   ASSERT_EQ(Json::nullValue, v["7052,1000"].type());
 
-  f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags), 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(7u, v.getMemberNames().size());
   ASSERT_TRUE(v.isMember("7050,1000"));
@@ -637,7 +642,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
   ASSERT_EQ("application/octet-stream", mime);
   ASSERT_EQ("Some unknown tag", content);
 
-  f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(8u, v.getMemberNames().size());
   ASSERT_TRUE(v.isMember("7050,1000"));
@@ -655,25 +660,25 @@ TEST(ParsedDicomFile, ToJsonFlags2)
   f.Insert(DICOM_TAG_PIXEL_DATA, "Pixels", false);
 
   Json::Value v;
-  f.ToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(5u, v.getMemberNames().size());
   ASSERT_FALSE(v.isMember("7fe0,0010"));  
 
-  f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData | DicomToJsonFlags_ConvertBinaryToNull), 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData | DicomToJsonFlags_ConvertBinaryToNull), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(6u, v.getMemberNames().size());
   ASSERT_TRUE(v.isMember("7fe0,0010"));  
   ASSERT_EQ(Json::nullValue, v["7fe0,0010"].type());  
 
-  f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData | DicomToJsonFlags_ConvertBinaryToAscii), 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData | DicomToJsonFlags_ConvertBinaryToAscii), 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(6u, v.getMemberNames().size());
   ASSERT_TRUE(v.isMember("7fe0,0010"));  
   ASSERT_EQ(Json::stringValue, v["7fe0,0010"].type());  
   ASSERT_EQ("Pixels", v["7fe0,0010"].asString());  
 
-  f.ToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludePixelData, 0);
+  f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludePixelData, 0);
   ASSERT_EQ(Json::objectValue, v.type());
   ASSERT_EQ(6u, v.getMemberNames().size());
   ASSERT_TRUE(v.isMember("7fe0,0010"));  
@@ -687,7 +692,7 @@ TEST(ParsedDicomFile, ToJsonFlags2)
 
 TEST(DicomFindAnswers, Basic)
 {
-  DicomFindAnswers a;
+  DicomFindAnswers a(false);
 
   {
     DicomMap m;
@@ -717,13 +722,17 @@ TEST(DicomFindAnswers, Basic)
 
 TEST(ParsedDicomFile, FromJson)
 {
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7057, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag", 1, 1);
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7059, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag", 1, 1);
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PersonName, "Declared public tag", 1, 1);
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7057, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag2", 1, 1, "ORTHANC");
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7059, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag3", 1, 1, "");
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PersonName, "Declared public tag2", 1, 1, "");
 
   Json::Value v;
   const std::string sopClassUid = "1.2.840.10008.5.1.4.1.1.1";  // CR Image Storage:
 
+  // Test the private creator
+  ASSERT_EQ(DcmTag_ERROR_TagName, FromDcmtkBridge::GetTagName(DicomTag(0x7057, 0x1000), "NOPE"));
+  ASSERT_EQ("MyPrivateTag2", FromDcmtkBridge::GetTagName(DicomTag(0x7057, 0x1000), "ORTHANC"));
+
   {
     v["SOPClassUID"] = sopClassUid;
     v["SpecificCharacterSet"] = "ISO_IR 148";    // This is latin-5
@@ -760,7 +769,7 @@ TEST(ParsedDicomFile, FromJson)
       (ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_GenerateIdentifiers)));
 
     Json::Value vv;
-    dicom->ToJson(vv, DicomToJsonFormat_Human, toJsonFlags, 0);
+    dicom->DatasetToJson(vv, DicomToJsonFormat_Human, toJsonFlags, 0);
 
     ASSERT_EQ(vv["SOPClassUID"].asString(), sopClassUid);
     ASSERT_EQ(vv["MediaStorageSOPClassUID"].asString(), sopClassUid);
@@ -776,7 +785,7 @@ TEST(ParsedDicomFile, FromJson)
       (ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_GenerateIdentifiers)));
 
     Json::Value vv;
-    dicom->ToJson(vv, DicomToJsonFormat_Human, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData), 0);
+    dicom->DatasetToJson(vv, DicomToJsonFormat_Human, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData), 0);
 
     std::string mime, content;
     ASSERT_TRUE(Toolbox::DecodeDataUriScheme(mime, content, vv["PixelData"].asString()));
@@ -790,7 +799,7 @@ TEST(ParsedDicomFile, FromJson)
       (ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_DecodeDataUriScheme)));
 
     Json::Value vv;
-    dicom->ToJson(vv, DicomToJsonFormat_Short, toJsonFlags, 0);
+    dicom->DatasetToJson(vv, DicomToJsonFormat_Short, toJsonFlags, 0);
 
     ASSERT_FALSE(vv.isMember("SOPInstanceUID"));
     ASSERT_FALSE(vv.isMember("SeriesInstanceUID"));
@@ -818,7 +827,7 @@ TEST(TestImages, PatternGrayscale8)
 {
   static const char* PATH = "UnitTestsResults/PatternGrayscale8.dcm";
 
-  Orthanc::Image image(Orthanc::PixelFormat_Grayscale8, 256, 256);
+  Orthanc::Image image(Orthanc::PixelFormat_Grayscale8, 256, 256, false);
 
   for (int y = 0; y < 256; y++)
   {
@@ -849,7 +858,7 @@ TEST(TestImages, PatternGrayscale8)
 
   {
     std::string s;
-    Orthanc::Toolbox::ReadFile(s, PATH);
+    Orthanc::SystemToolbox::ReadFile(s, PATH);
     Orthanc::ParsedDicomFile f(s);
     
     std::auto_ptr<Orthanc::ImageAccessor> decoded(Orthanc::DicomImageDecoder::Decode(f, 0));
@@ -871,7 +880,7 @@ TEST(TestImages, PatternRGB)
 {
   static const char* PATH = "UnitTestsResults/PatternRGB24.dcm";
 
-  Orthanc::Image image(Orthanc::PixelFormat_RGB24, 384, 256);
+  Orthanc::Image image(Orthanc::PixelFormat_RGB24, 384, 256, false);
 
   for (int y = 0; y < 256; y++)
   {
@@ -911,7 +920,7 @@ TEST(TestImages, PatternRGB)
 
   {
     std::string s;
-    Orthanc::Toolbox::ReadFile(s, PATH);
+    Orthanc::SystemToolbox::ReadFile(s, PATH);
     Orthanc::ParsedDicomFile f(s);
     
     std::auto_ptr<Orthanc::ImageAccessor> decoded(Orthanc::DicomImageDecoder::Decode(f, 0));
@@ -933,7 +942,7 @@ TEST(TestImages, PatternUint16)
 {
   static const char* PATH = "UnitTestsResults/PatternGrayscale16.dcm";
 
-  Orthanc::Image image(Orthanc::PixelFormat_Grayscale16, 256, 256);
+  Orthanc::Image image(Orthanc::PixelFormat_Grayscale16, 256, 256, false);
 
   uint16_t v = 0;
   for (int y = 0; y < 256; y++)
@@ -965,7 +974,7 @@ TEST(TestImages, PatternUint16)
 
   {
     std::string s;
-    Orthanc::Toolbox::ReadFile(s, PATH);
+    Orthanc::SystemToolbox::ReadFile(s, PATH);
     Orthanc::ParsedDicomFile f(s);
     
     std::auto_ptr<Orthanc::ImageAccessor> decoded(Orthanc::DicomImageDecoder::Decode(f, 0));
@@ -987,7 +996,7 @@ TEST(TestImages, PatternInt16)
 {
   static const char* PATH = "UnitTestsResults/PatternSignedGrayscale16.dcm";
 
-  Orthanc::Image image(Orthanc::PixelFormat_SignedGrayscale16, 256, 256);
+  Orthanc::Image image(Orthanc::PixelFormat_SignedGrayscale16, 256, 256, false);
 
   int16_t v = -32768;
   for (int y = 0; y < 256; y++)
@@ -1019,7 +1028,7 @@ TEST(TestImages, PatternInt16)
 
   {
     std::string s;
-    Orthanc::Toolbox::ReadFile(s, PATH);
+    Orthanc::SystemToolbox::ReadFile(s, PATH);
     Orthanc::ParsedDicomFile f(s);
     
     std::auto_ptr<Orthanc::ImageAccessor> decoded(Orthanc::DicomImageDecoder::Decode(f, 0));
@@ -1035,3 +1044,175 @@ TEST(TestImages, PatternInt16)
     }
   }
 }
+
+
+
+static void CheckEncoding(const ParsedDicomFile& dicom,
+                          Encoding expected)
+{
+  const char* value = NULL;
+  ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->findAndGetString(DCM_SpecificCharacterSet, value).good());
+
+  Encoding encoding;
+  ASSERT_TRUE(GetDicomEncoding(encoding, value));
+  ASSERT_EQ(expected, encoding);
+}
+
+
+TEST(ParsedDicomFile, DicomMapEncodings1)
+{
+  Configuration::SetDefaultEncoding(Encoding_Ascii);
+  ASSERT_EQ(Encoding_Ascii, Configuration::GetDefaultEncoding());
+
+  {
+    DicomMap m;
+    ParsedDicomFile dicom(m);
+    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    CheckEncoding(dicom, Encoding_Ascii);
+  }
+
+  {
+    DicomMap m;
+    ParsedDicomFile dicom(m, Encoding_Latin4);
+    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    CheckEncoding(dicom, Encoding_Latin4);
+  }
+
+  {
+    DicomMap m;
+    m.SetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET, "ISO_IR 148", false);
+    ParsedDicomFile dicom(m);
+    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    CheckEncoding(dicom, Encoding_Latin5);
+  }
+
+  {
+    DicomMap m;
+    m.SetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET, "ISO_IR 148", false);
+    ParsedDicomFile dicom(m, Encoding_Latin1);
+    ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+    CheckEncoding(dicom, Encoding_Latin5);
+  }
+}
+
+
+TEST(ParsedDicomFile, DicomMapEncodings2)
+{
+  const char* utf8 = NULL;
+  for (unsigned int i = 0; i < testEncodingsCount; i++)
+  {
+    if (testEncodings[i] == Encoding_Utf8)
+    {
+      utf8 = testEncodingsEncoded[i];
+      break;
+    }
+  }  
+
+  ASSERT_TRUE(utf8 != NULL);
+
+  for (unsigned int i = 0; i < testEncodingsCount; i++)
+  {
+    // 1251 codepage is not supported by the core DICOM standard, ignore it
+    if (testEncodings[i] != Encoding_Windows1251) 
+    {
+      {
+        // Sanity check to test the proper behavior of "EncodingTests.py"
+        std::string encoded = Toolbox::ConvertFromUtf8(testEncodingsExpected[i], testEncodings[i]);
+        ASSERT_STREQ(testEncodingsEncoded[i], encoded.c_str());
+        std::string decoded = Toolbox::ConvertToUtf8(encoded, testEncodings[i]);
+        ASSERT_STREQ(testEncodingsExpected[i], decoded.c_str());
+
+        if (testEncodings[i] != Encoding_Chinese)
+        {
+          // A specific source string is used in "EncodingTests.py" to
+          // test against Chinese, it is normal that it does not correspond to UTF8
+
+          std::string encoded = Toolbox::ConvertToUtf8(Toolbox::ConvertFromUtf8(utf8, testEncodings[i]), testEncodings[i]);
+          ASSERT_STREQ(testEncodingsExpected[i], encoded.c_str());
+        }
+      }
+
+
+      Json::Value v;
+
+      {
+        DicomMap m;
+        m.SetValue(DICOM_TAG_PATIENT_NAME, testEncodingsExpected[i], false);
+
+        ParsedDicomFile dicom(m, testEncodings[i]);
+    
+        const char* encoded = NULL;
+        ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->findAndGetString(DCM_PatientName, encoded).good());
+        ASSERT_STREQ(testEncodingsEncoded[i], encoded);
+
+        dicom.DatasetToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+
+        Encoding encoding;
+        ASSERT_TRUE(GetDicomEncoding(encoding, v["SpecificCharacterSet"].asCString()));
+        ASSERT_EQ(encoding, testEncodings[i]);
+        ASSERT_STREQ(testEncodingsExpected[i], v["PatientName"].asCString());
+      }
+
+
+      {
+        DicomMap m;
+        m.SetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET, GetDicomSpecificCharacterSet(testEncodings[i]), false);
+        m.SetValue(DICOM_TAG_PATIENT_NAME, testEncodingsExpected[i], false);
+
+        ParsedDicomFile dicom(m, testEncodings[i]);
+
+        Json::Value v2;
+        dicom.DatasetToJson(v2, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+        
+        ASSERT_EQ(v2["PatientName"].asString(), v["PatientName"].asString());
+        ASSERT_EQ(v2["SpecificCharacterSet"].asString(), v["SpecificCharacterSet"].asString());
+      }
+    }
+  }
+}
+
+
+TEST(ParsedDicomFile, ChangeEncoding)
+{
+  for (unsigned int i = 0; i < testEncodingsCount; i++)
+  {
+    // 1251 codepage is not supported by the core DICOM standard, ignore it
+    if (testEncodings[i] != Encoding_Windows1251) 
+    {
+      DicomMap m;
+      m.SetValue(DICOM_TAG_PATIENT_NAME, testEncodingsExpected[i], false);
+
+      std::string tag;
+
+      ParsedDicomFile dicom(m, Encoding_Utf8);
+      ASSERT_EQ(Encoding_Utf8, dicom.GetEncoding());
+      ASSERT_TRUE(dicom.GetTagValue(tag, DICOM_TAG_PATIENT_NAME));
+      ASSERT_EQ(tag, testEncodingsExpected[i]);
+
+      {
+        Json::Value v;
+        dicom.DatasetToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+        ASSERT_STREQ(v["SpecificCharacterSet"].asCString(), "ISO_IR 192");
+        ASSERT_STREQ(v["PatientName"].asCString(), testEncodingsExpected[i]);
+      }
+
+      dicom.ChangeEncoding(testEncodings[i]);
+
+      ASSERT_EQ(testEncodings[i], dicom.GetEncoding());
+      
+      const char* c = NULL;
+      ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->findAndGetString(DCM_PatientName, c).good());
+      EXPECT_STREQ(c, testEncodingsEncoded[i]);
+      
+      ASSERT_TRUE(dicom.GetTagValue(tag, DICOM_TAG_PATIENT_NAME));  // Decodes to UTF-8
+      EXPECT_EQ(tag, testEncodingsExpected[i]);
+
+      {
+        Json::Value v;
+        dicom.DatasetToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+        ASSERT_STREQ(v["SpecificCharacterSet"].asCString(), GetDicomSpecificCharacterSet(testEncodings[i]));
+        ASSERT_STREQ(v["PatientName"].asCString(), testEncodingsExpected[i]);
+      }
+    }
+  }
+}
diff --git a/UnitTestsSources/ImageTests.cpp b/UnitTestsSources/ImageTests.cpp
index 7fc5c77..6c7ed55 100644
--- a/UnitTestsSources/ImageTests.cpp
+++ b/UnitTestsSources/ImageTests.cpp
@@ -41,7 +41,7 @@
 #include "../Core/Images/PngReader.h"
 #include "../Core/Images/PngWriter.h"
 #include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
+#include "../Core/TemporaryFile.h"
 #include "../OrthancServer/OrthancInitialization.h"
 
 #include <stdint.h>
@@ -72,7 +72,7 @@ TEST(PngWriter, ColorPattern)
   w.WriteToFile("UnitTestsResults/ColorPattern.png", accessor);
 
   std::string f, md5;
-  Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/ColorPattern.png");
+  Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/ColorPattern.png");
   Orthanc::Toolbox::ComputeMD5(md5, f);
   ASSERT_EQ("604e785f53c99cae6ea4584870b2c41d", md5);
 }
@@ -100,7 +100,7 @@ TEST(PngWriter, Gray8Pattern)
   w.WriteToFile("UnitTestsResults/Gray8Pattern.png", accessor);
 
   std::string f, md5;
-  Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/Gray8Pattern.png");
+  Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/Gray8Pattern.png");
   Orthanc::Toolbox::ComputeMD5(md5, f);
   ASSERT_EQ("5a9b98bea3d0a6d983980cc38bfbcdb3", md5);
 }
@@ -129,7 +129,7 @@ TEST(PngWriter, Gray16Pattern)
   w.WriteToFile("UnitTestsResults/Gray16Pattern.png", accessor);
 
   std::string f, md5;
-  Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/Gray16Pattern.png");
+  Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/Gray16Pattern.png");
   Orthanc::Toolbox::ComputeMD5(md5, f);
   ASSERT_EQ("0785866a08bf0a02d2eeff87f658571c", md5);
 }
@@ -180,8 +180,8 @@ TEST(PngWriter, EndToEnd)
   }
 
   {
-    Orthanc::Toolbox::TemporaryFile tmp;
-    Orthanc::Toolbox::WriteFile(s, tmp.GetPath());
+    Orthanc::TemporaryFile tmp;
+    Orthanc::SystemToolbox::WriteFile(s, tmp.GetPath());
 
     Orthanc::PngReader r2;
     r2.ReadFromFile(tmp.GetPath());
@@ -211,7 +211,7 @@ TEST(JpegWriter, Basic)
   std::string s;
 
   {
-    Orthanc::Image img(Orthanc::PixelFormat_Grayscale8, 16, 16);
+    Orthanc::Image img(Orthanc::PixelFormat_Grayscale8, 16, 16, false);
     for (unsigned int y = 0, value = 0; y < img.GetHeight(); y++)
     {
       uint8_t* p = reinterpret_cast<uint8_t*>(img.GetRow(y));
@@ -225,10 +225,10 @@ TEST(JpegWriter, Basic)
     w.WriteToFile("UnitTestsResults/hello.jpg", img);
 
     w.WriteToMemory(s, img);
-    Orthanc::Toolbox::WriteFile(s, "UnitTestsResults/hello2.jpg");
+    Orthanc::SystemToolbox::WriteFile(s, "UnitTestsResults/hello2.jpg");
 
     std::string t;
-    Orthanc::Toolbox::ReadFile(t, "UnitTestsResults/hello.jpg");
+    Orthanc::SystemToolbox::ReadFile(t, "UnitTestsResults/hello.jpg");
     ASSERT_EQ(s.size(), t.size());
     ASSERT_EQ(0, memcmp(s.c_str(), t.c_str(), s.size()));
   }
@@ -258,7 +258,7 @@ TEST(JpegWriter, Basic)
 
 TEST(Font, Basic)
 {
-  Orthanc::Image s(Orthanc::PixelFormat_RGB24, 640, 480);
+  Orthanc::Image s(Orthanc::PixelFormat_RGB24, 640, 480, false);
   memset(s.GetBuffer(), 0, s.GetPitch() * s.GetHeight());
 
   ASSERT_GE(1u, Orthanc::Configuration::GetFontRegistry().GetSize());
diff --git a/UnitTestsSources/JpegLosslessTests.cpp b/UnitTestsSources/JpegLosslessTests.cpp
index a50fb6f..c52eebe 100644
--- a/UnitTestsSources/JpegLosslessTests.cpp
+++ b/UnitTestsSources/JpegLosslessTests.cpp
@@ -35,7 +35,7 @@
 
 #include "../OrthancServer/Internals/DicomImageDecoder.h"
 
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
 
 #include <dcmtk/dcmdata/dcfilefo.h>
 
diff --git a/UnitTestsSources/LuaTests.cpp b/UnitTestsSources/LuaTests.cpp
index 1453250..52e9afd 100644
--- a/UnitTestsSources/LuaTests.cpp
+++ b/UnitTestsSources/LuaTests.cpp
@@ -287,8 +287,8 @@ TEST(Lua, Http)
   Orthanc::LuaContext lua;
 
 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1  
-  lua.Execute("JSON = loadstring(HttpGet('http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/JSON.lua')) ()");
-  const std::string url("http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/Product.json");
+  lua.Execute("JSON = loadstring(HttpGet('http://www.orthanc-server.com/downloads/third-party/JSON.lua')) ()");
+  const std::string url("http://www.orthanc-server.com/downloads/third-party/Product.json");
 #endif
 
   std::string s;
diff --git a/UnitTestsSources/MultiThreadingTests.cpp b/UnitTestsSources/MultiThreadingTests.cpp
index 8ccfd15..bc1154f 100644
--- a/UnitTestsSources/MultiThreadingTests.cpp
+++ b/UnitTestsSources/MultiThreadingTests.cpp
@@ -35,6 +35,7 @@
 
 #include "../OrthancServer/Scheduler/ServerScheduler.h"
 #include "../Core/OrthancException.h"
+#include "../Core/SystemToolbox.h"
 #include "../Core/Toolbox.h"
 #include "../Core/MultiThreading/Locker.h"
 #include "../Core/MultiThreading/Mutex.h"
@@ -138,7 +139,7 @@ TEST(ReusableDicomUserConnection, DISABLED_Basic)
   {
     RemoteModalityParameters remote("STORESCP", "localhost", 2000, ModalityManufacturer_Generic);
     ReusableDicomUserConnection::Locker lock(c, "ORTHANC", remote);
-    lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676281", 0);
+    lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676281");
   }
 
   printf("**\n"); fflush(stdout);
@@ -148,10 +149,10 @@ TEST(ReusableDicomUserConnection, DISABLED_Basic)
   {
     RemoteModalityParameters remote("STORESCP", "localhost", 2000, ModalityManufacturer_Generic);
     ReusableDicomUserConnection::Locker lock(c, "ORTHANC", remote);
-    lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676277", 0);
+    lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676277");
   }
 
-  Toolbox::ServerBarrier();
+  SystemToolbox::ServerBarrier();
   printf("DONE\n"); fflush(stdout);
 }
 
@@ -246,7 +247,7 @@ TEST(MultiThreading, ServerScheduler)
     printf("** %s\n", i->c_str());
   }
 
-  //Toolbox::ServerBarrier();
+  //SystemToolbox::ServerBarrier();
   //Toolbox::USleep(3000000);
 
   scheduler.Stop();
diff --git a/UnitTestsSources/PluginsTests.cpp b/UnitTestsSources/PluginsTests.cpp
index 516e140..4bd0f92 100644
--- a/UnitTestsSources/PluginsTests.cpp
+++ b/UnitTestsSources/PluginsTests.cpp
@@ -38,7 +38,7 @@
 using namespace Orthanc;
 
 
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
 
 TEST(SharedLibrary, Enumerations)
 {
diff --git a/UnitTestsSources/RestApiTests.cpp b/UnitTestsSources/RestApiTests.cpp
index c60e6fc..03102a6 100644
--- a/UnitTestsSources/RestApiTests.cpp
+++ b/UnitTestsSources/RestApiTests.cpp
@@ -40,8 +40,8 @@
 #include "../Core/ChunkedBuffer.h"
 #include "../Core/HttpClient.h"
 #include "../Core/Logging.h"
+#include "../Core/SystemToolbox.h"
 #include "../Core/RestApi/RestApi.h"
-#include "../Core/Uuid.h"
 #include "../Core/OrthancException.h"
 #include "../Core/Compression/ZlibCompressor.h"
 #include "../Core/RestApi/RestApiHierarchy.h"
@@ -66,14 +66,15 @@ TEST(HttpClient, Basic)
 
 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1
   Json::Value v;
-  c.SetUrl("http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/Configuration.json");
+  c.SetUrl("http://www.orthanc-server.com/downloads/third-party/Product.json");
   c.Apply(v);
-  ASSERT_TRUE(v.isMember("StorageDirectory"));
+  ASSERT_TRUE(v.type() == Json::objectValue);
+  ASSERT_TRUE(v.isMember("Description"));
 #endif
 }
 
 
-#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 && ORTHANC_SSL_ENABLED == 1
+#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 && ORTHANC_ENABLE_SSL == 1
 
 /**
    The HTTPS CA certificates for BitBucket were extracted as follows:
@@ -100,12 +101,12 @@ TEST(HttpClient, Basic)
 
 TEST(HttpClient, Ssl)
 {
-  Toolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert");
+  SystemToolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert");
 
   /*{
     std::string s;
-    Toolbox::ReadFile(s, "/usr/share/ca-certificates/mozilla/WoSign.crt");
-    Toolbox::WriteFile(s, "UnitTestsResults/bitbucket.cert");
+    SystemToolbox::ReadFile(s, "/usr/share/ca-certificates/mozilla/WoSign.crt");
+    SystemToolbox::WriteFile(s, "UnitTestsResults/bitbucket.cert");
     }*/
 
   HttpClient c;
diff --git a/UnitTestsSources/SQLiteTests.cpp b/UnitTestsSources/SQLiteTests.cpp
index c3ddafc..9b39ab9 100644
--- a/UnitTestsSources/SQLiteTests.cpp
+++ b/UnitTestsSources/SQLiteTests.cpp
@@ -33,7 +33,7 @@
 #include "PrecompiledHeadersUnitTests.h"
 #include "gtest/gtest.h"
 
-#include "../Core/Toolbox.h"
+#include "../Core/SystemToolbox.h"
 #include "../Core/SQLite/Connection.h"
 #include "../Core/SQLite/Statement.h"
 #include "../Core/SQLite/Transaction.h"
@@ -58,7 +58,7 @@ TEST(SQLite, Configuration)
 
 TEST(SQLite, Connection)
 {
-  Toolbox::RemoveFile("UnitTestsResults/coucou");
+  SystemToolbox::RemoveFile("UnitTestsResults/coucou");
   SQLite::Connection c;
   c.Open("UnitTestsResults/coucou");
   c.Execute("CREATE TABLE c(k INTEGER PRIMARY KEY AUTOINCREMENT, v INTEGER)");
diff --git a/UnitTestsSources/ServerIndexTests.cpp b/UnitTestsSources/ServerIndexTests.cpp
index 4dd7233..8fe8094 100644
--- a/UnitTestsSources/ServerIndexTests.cpp
+++ b/UnitTestsSources/ServerIndexTests.cpp
@@ -35,7 +35,6 @@
 
 #include "../Core/FileStorage/FilesystemStorage.h"
 #include "../Core/Logging.h"
-#include "../Core/Uuid.h"
 #include "../OrthancServer/DatabaseWrapper.h"
 #include "../OrthancServer/ServerContext.h"
 #include "../OrthancServer/ServerIndex.h"
@@ -671,7 +670,7 @@ TEST(ServerIndex, Sequence)
 {
   const std::string path = "UnitTestsStorage";
 
-  Toolbox::RemoveFile(path + "/index");
+  SystemToolbox::RemoveFile(path + "/index");
   FilesystemStorage storage(path);
   DatabaseWrapper db;   // The SQLite DB is in memory
   db.Open();
@@ -769,7 +768,7 @@ TEST(ServerIndex, AttachmentRecycling)
 {
   const std::string path = "UnitTestsStorage";
 
-  Toolbox::RemoveFile(path + "/index");
+  SystemToolbox::RemoveFile(path + "/index");
   FilesystemStorage storage(path);
   DatabaseWrapper db;   // The SQLite DB is in memory
   db.Open();
@@ -794,14 +793,22 @@ TEST(ServerIndex, AttachmentRecycling)
     instance.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "study-" + id, false);
     instance.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "series-" + id, false);
     instance.SetValue(DICOM_TAG_SOP_INSTANCE_UID, "instance-" + id, false);
+    instance.SetValue(DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.1", false);  // CR image
 
     std::map<MetadataType, std::string> instanceMetadata;
     DicomInstanceToStore toStore;
     toStore.SetSummary(instance);
     ASSERT_EQ(StoreStatus_Success, index.Store(instanceMetadata, toStore, attachments));
-    ASSERT_EQ(3u, instanceMetadata.size());
+    ASSERT_EQ(5u, instanceMetadata.size());
     ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_RemoteAet) != instanceMetadata.end());
     ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_ReceptionDate) != instanceMetadata.end());
+    ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_TransferSyntax) != instanceMetadata.end());
+    ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_SopClassUid) != instanceMetadata.end());
+
+    // By default, an Explicit VR Little Endian is used by Orthanc
+    ASSERT_EQ("1.2.840.10008.1.2.1", instanceMetadata[MetadataType_Instance_TransferSyntax]);
+
+    ASSERT_EQ("1.2.840.10008.5.1.4.1.1.1", instanceMetadata[MetadataType_Instance_SopClassUid]);
 
     DicomInstanceHasher hasher(instance);
     ids.push_back(hasher.HashPatient());
@@ -816,7 +823,7 @@ TEST(ServerIndex, AttachmentRecycling)
 
   for (size_t i = 0; i < ids.size(); i++)
   {
-    FileInfo info(Toolbox::GenerateUuid(), FileContentType_Dicom, 1, "md5");
+    FileInfo info(SystemToolbox::GenerateUuid(), FileContentType_Dicom, 1, "md5");
     index.AddAttachment(info, ids[i]);
 
     index.ComputeStatistics(tmp);
@@ -824,7 +831,7 @@ TEST(ServerIndex, AttachmentRecycling)
   }
 
   // Because the DB is in memory, the SQLite index must not have been created
-  ASSERT_FALSE(Toolbox::IsRegularFile(path + "/index"));
+  ASSERT_FALSE(SystemToolbox::IsRegularFile(path + "/index"));
 
   context.Stop();
   db.Close();
@@ -833,6 +840,6 @@ TEST(ServerIndex, AttachmentRecycling)
 
 TEST(LookupIdentifierQuery, NormalizeIdentifier)
 {
-  ASSERT_EQ("H^L.LO", LookupIdentifierQuery::NormalizeIdentifier("   Hé^l.LO  %_  "));
-  ASSERT_EQ("1.2.840.113619.2.176.2025", LookupIdentifierQuery::NormalizeIdentifier("   1.2.840.113619.2.176.2025  "));
+  ASSERT_EQ("H^L.LO", ServerToolbox::NormalizeIdentifier("   Hé^l.LO  %_  "));
+  ASSERT_EQ("1.2.840.113619.2.176.2025", ServerToolbox::NormalizeIdentifier("   1.2.840.113619.2.176.2025  "));
 }
diff --git a/UnitTestsSources/StreamTests.cpp b/UnitTestsSources/StreamTests.cpp
index 397c25b..bf95796 100644
--- a/UnitTestsSources/StreamTests.cpp
+++ b/UnitTestsSources/StreamTests.cpp
@@ -33,9 +33,10 @@
 #include "PrecompiledHeadersUnitTests.h"
 #include "gtest/gtest.h"
 
+#include "../Core/SystemToolbox.h"
+#include "../Core/SystemToolbox.h"
 #include "../Core/Toolbox.h"
 #include "../Core/OrthancException.h"
-#include "../Core/Uuid.h"
 #include "../Core/HttpServer/BufferHttpSender.h"
 #include "../Core/HttpServer/FilesystemHttpSender.h"
 #include "../Core/HttpServer/HttpStreamTranscoder.h"
@@ -113,7 +114,7 @@ TEST(Gzip, EmptyWithPrefix)
 
 TEST(Zlib, Basic)
 {
-  std::string s = Toolbox::GenerateUuid();
+  std::string s = SystemToolbox::GenerateUuid();
   s = s + s + s + s;
  
   std::string compressed, compressed2;
@@ -130,7 +131,7 @@ TEST(Zlib, Basic)
 
 TEST(Zlib, Level)
 {
-  std::string s = Toolbox::GenerateUuid();
+  std::string s = SystemToolbox::GenerateUuid();
   s = s + s + s + s;
  
   std::string compressed, compressed2;
@@ -147,7 +148,7 @@ TEST(Zlib, Level)
 
 TEST(Zlib, DISABLED_Corrupted)  // Disabled because it may result in a crash
 {
-  std::string s = Toolbox::GenerateUuid();
+  std::string s = SystemToolbox::GenerateUuid();
   s = s + s + s + s;
  
   std::string compressed;
@@ -233,14 +234,14 @@ TEST(FilesystemHttpSender, Basic)
   std::string t;
 
   {
-    Toolbox::WriteFile(s, path);
+    SystemToolbox::WriteFile(s, path);
     FilesystemHttpSender sender(path);
     ASSERT_TRUE(ReadAllStream(t, sender));
     ASSERT_EQ(s, t);
   }
 
   {
-    Toolbox::WriteFile("", path);
+    SystemToolbox::WriteFile("", path);
     FilesystemHttpSender sender(path);
     ASSERT_TRUE(ReadAllStream(t, sender));
     ASSERT_EQ(0u, t.size());
@@ -252,7 +253,7 @@ TEST(HttpStreamTranscoder, Basic)
 {
   ZlibCompressor compressor;
 
-  const std::string s = "Hello world " + Toolbox::GenerateUuid();
+  const std::string s = "Hello world " + SystemToolbox::GenerateUuid();
 
   std::string t;
   IBufferCompressor::Compress(t, compressor, s);
diff --git a/UnitTestsSources/UnitTestsMain.cpp b/UnitTestsSources/UnitTestsMain.cpp
index 42882e2..59c7193 100644
--- a/UnitTestsSources/UnitTestsMain.cpp
+++ b/UnitTestsSources/UnitTestsMain.cpp
@@ -41,8 +41,8 @@
 #include "../Core/HttpServer/HttpToolbox.h"
 #include "../Core/Logging.h"
 #include "../Core/OrthancException.h"
+#include "../Core/TemporaryFile.h"
 #include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
 #include "../OrthancServer/OrthancInitialization.h"
 
 
@@ -53,7 +53,7 @@ TEST(Uuid, Generation)
 {
   for (int i = 0; i < 10; i++)
   {
-    std::string s = Toolbox::GenerateUuid();
+    std::string s = SystemToolbox::GenerateUuid();
     ASSERT_TRUE(Toolbox::IsUuid(s));
   }
 }
@@ -374,8 +374,8 @@ TEST(Toolbox, Base64)
 
 TEST(Toolbox, PathToExecutable)
 {
-  printf("[%s]\n", Toolbox::GetPathToExecutable().c_str());
-  printf("[%s]\n", Toolbox::GetDirectoryOfExecutable().c_str());
+  printf("[%s]\n", SystemToolbox::GetPathToExecutable().c_str());
+  printf("[%s]\n", SystemToolbox::GetDirectoryOfExecutable().c_str());
 }
 
 TEST(Toolbox, StripSpaces)
@@ -543,7 +543,7 @@ TEST(Toolbox, WriteFile)
   std::string path;
 
   {
-    Toolbox::TemporaryFile tmp;
+    TemporaryFile tmp;
     path = tmp.GetPath();
 
     std::string s;
@@ -552,28 +552,28 @@ TEST(Toolbox, WriteFile)
     s.append("World");
     ASSERT_EQ(11u, s.size());
 
-    Toolbox::WriteFile(s, path.c_str());
+    SystemToolbox::WriteFile(s, path.c_str());
 
     std::string t;
-    Toolbox::ReadFile(t, path.c_str());
+    SystemToolbox::ReadFile(t, path.c_str());
 
     ASSERT_EQ(11u, t.size());
     ASSERT_EQ(0, t[5]);
     ASSERT_EQ(0, memcmp(s.c_str(), t.c_str(), s.size()));
 
     std::string h;
-    ASSERT_EQ(true, Toolbox::ReadHeader(h, path.c_str(), 1));
+    ASSERT_EQ(true, SystemToolbox::ReadHeader(h, path.c_str(), 1));
     ASSERT_EQ(1u, h.size());
     ASSERT_EQ('H', h[0]);
-    ASSERT_TRUE(Toolbox::ReadHeader(h, path.c_str(), 0));
+    ASSERT_TRUE(SystemToolbox::ReadHeader(h, path.c_str(), 0));
     ASSERT_EQ(0u, h.size());
-    ASSERT_FALSE(Toolbox::ReadHeader(h, path.c_str(), 32));
+    ASSERT_FALSE(SystemToolbox::ReadHeader(h, path.c_str(), 32));
     ASSERT_EQ(11u, h.size());
     ASSERT_EQ(0, memcmp(s.c_str(), h.c_str(), s.size()));
   }
 
   std::string u;
-  ASSERT_THROW(Toolbox::ReadFile(u, path.c_str()), OrthancException);
+  ASSERT_THROW(SystemToolbox::ReadFile(u, path.c_str()), OrthancException);
 }
 
 
@@ -871,7 +871,7 @@ TEST(Toolbox, EndiannessConversions64)
 
 
 
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
 TEST(Toolbox, Xml)
 {
   Json::Value a;
@@ -896,7 +896,7 @@ TEST(Toolbox, ExecuteSystemCommand)
   args[0] = "Hello";
   args[1] = "World";
 
-  Toolbox::ExecuteSystemCommand("echo", args);
+  SystemToolbox::ExecuteSystemCommand("echo", args);
 }
 #endif
 
@@ -945,12 +945,49 @@ TEST(Toolbox, UriEncode)
 }
 
 
+TEST(Toolbox, AccessJson)
+{
+  Json::Value v = Json::arrayValue;
+  ASSERT_EQ("nope", Toolbox::GetJsonStringField(v, "hello", "nope"));
+
+  v = Json::objectValue;
+  ASSERT_EQ("nope", Toolbox::GetJsonStringField(v, "hello", "nope"));
+  ASSERT_EQ(-10, Toolbox::GetJsonIntegerField(v, "hello", -10));
+  ASSERT_EQ(10, Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10));
+  ASSERT_TRUE(Toolbox::GetJsonBooleanField(v, "hello", true));
+
+  v["hello"] = "world";
+  ASSERT_EQ("world", Toolbox::GetJsonStringField(v, "hello", "nope"));
+  ASSERT_THROW(Toolbox::GetJsonIntegerField(v, "hello", -10), OrthancException);
+  ASSERT_THROW(Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10), OrthancException);
+  ASSERT_THROW(Toolbox::GetJsonBooleanField(v, "hello", true), OrthancException);
+
+  v["hello"] = -42;
+  ASSERT_THROW(Toolbox::GetJsonStringField(v, "hello", "nope"), OrthancException);
+  ASSERT_EQ(-42, Toolbox::GetJsonIntegerField(v, "hello", -10));
+  ASSERT_THROW(Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10), OrthancException);
+  ASSERT_THROW(Toolbox::GetJsonBooleanField(v, "hello", true), OrthancException);
+
+  v["hello"] = 42;
+  ASSERT_THROW(Toolbox::GetJsonStringField(v, "hello", "nope"), OrthancException);
+  ASSERT_EQ(42, Toolbox::GetJsonIntegerField(v, "hello", -10));
+  ASSERT_EQ(42, Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10));
+  ASSERT_THROW(Toolbox::GetJsonBooleanField(v, "hello", true), OrthancException);
+
+  v["hello"] = false;
+  ASSERT_THROW(Toolbox::GetJsonStringField(v, "hello", "nope"), OrthancException);
+  ASSERT_THROW(Toolbox::GetJsonIntegerField(v, "hello", -10), OrthancException);
+  ASSERT_THROW(Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10), OrthancException);
+  ASSERT_FALSE(Toolbox::GetJsonBooleanField(v, "hello", true));
+}
+
+
 int main(int argc, char **argv)
 {
   Logging::Initialize();
   Logging::EnableInfoLevel(true);
   Toolbox::DetectEndianness();
-  Toolbox::MakeDirectory("UnitTestsResults");
+  SystemToolbox::MakeDirectory("UnitTestsResults");
   OrthancInitialize();
 
   ::testing::InitGoogleTest(&argc, argv);
diff --git a/UnitTestsSources/VersionsTests.cpp b/UnitTestsSources/VersionsTests.cpp
index f9b738a..193ce72 100644
--- a/UnitTestsSources/VersionsTests.cpp
+++ b/UnitTestsSources/VersionsTests.cpp
@@ -44,7 +44,7 @@
 #include <lua.h>
 #include <jpeglib.h>
 
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
 #include <openssl/opensslv.h>
 #endif
 
@@ -108,7 +108,7 @@ TEST(Versions, BoostStatic)
 TEST(Versions, CurlStatic)
 {
   curl_version_info_data* v = curl_version_info(CURLVERSION_NOW);
-  ASSERT_STREQ("7.44.0", v->version);
+  ASSERT_STREQ("7.50.3", v->version);
 }
 
 TEST(Versions, PngStatic)
@@ -130,7 +130,7 @@ TEST(Versions, CurlSslStatic)
   // Check that SSL support is enabled when required
   bool curlSupportsSsl = (vinfo->features & CURL_VERSION_SSL) != 0;
 
-#if ORTHANC_SSL_ENABLED == 0
+#if ORTHANC_ENABLE_SSL == 0
   ASSERT_FALSE(curlSupportsSsl);
 #else
   ASSERT_TRUE(curlSupportsSsl);
@@ -143,7 +143,7 @@ TEST(Version, LuaStatic)
 }
 
 
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
 TEST(Version, OpenSslStatic)
 {
   ASSERT_EQ(0x1000204fL /* openssl-1.0.2d */, OPENSSL_VERSION_NUMBER);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/orthanc.git



More information about the debian-med-commit mailing list